Hallo, ich frage mich, wie Sie eine SQL-Anweisung für SQL Server 2008 schreiben, in der Einträge ausgewählt werden, in denen eine Spalte einen Wert enthält. Jetzt ist der Wert in der Spalte eine durch Kommas getrennte Liste (normalerweise - es könnte nur einen Eintrag geben (und kein führendes Komma). ) Was ist beim Überprüfen auf "Ist dieser Wert irgendwo in der Liste enthalten?", zum Beispiel:
COLUMN = Cat, Dog, Sparrow, Trout, Cow, Seahorse
Does COLUMN contain Cat? YES
Does COLUMN contain horse? NO
Does COLUMN contain Sheep? NO
oder
COLUMN = Mouse
Does COLUMN contain Hare? NO
Does COLUMN contain Mouse? YES
usw
Ich dachte, ich könnte das Schlüsselwort 'IN' als solches verwenden
SELECT id_column FROM table_name WHERE 'Cat' IN COLUMN
dies funktioniert jedoch nicht, da es so aussieht, als könnten Sie dies nur verwenden, um zu überprüfen, ob eine Spalte einen aus einer Reihe von durch Kommas getrennten Wert enthält.
CONTAINS () OR 'LIKE' kann ich auch nicht verwenden, da im obigen Beispiel Werte für 'horse' zurückgegeben würden, da die gesamte Zeichenfolge Pferd in 'Seahorse' enthält und ich nicht nach der Nadel plus suchen kann ein Komma (wenn ich nach "Pferd" suche, wäre die Suche "Pferd") als was, wenn der Eintrag am Ende einer Liste steht? Und ich kann nicht nach einem Komma und einer Nadel suchen (wenn ich nach 'Pferd' suche, wäre das 'Pferd') Was wäre, wenn der Eintrag der erste in der Liste ist? Und ich kann nicht beides als was verwenden, wenn der Eintrag der einzige (einzelne) Eintrag ist?
Danke für jede Hilfe, die jeder geben kann.
Prost.
Es gibt ein schwieriges Szenario. Wenn ich nach '40' in der Liste '17, 34,400,12 'suche, würde es ", 40" finden und diesen falschen Eintrag zurückgeben. Dies kümmert sich um alle Lösungen:
WHERE (',' + RTRIM(MyColumn) + ',') LIKE '%,' + @search + ',%'
WHERE
MyColumn LIKE '%,' + @search + ',%' --middle
OR
MyColumn LIKE @search + ',%' --start
OR
MyColumn LIKE '%,' + @search --end
OR
MyColumn = @search --single (good point by Cheran S in comment)
SELECT * FROM TABLENAME WHERE FIND_IN_SET(@search, column)
Wenn sich herausstellt, dass Ihre Spalte zwischen den Listenelementen Leerzeichen enthält, verwenden Sie
SELECT * FROM TABLENAME WHERE FIND_IN_SET(@search, REPLACE(column, ' ', ''))
http://dev.mysql.com/doc/refman/5.0/de/string-functions.html
DECLARE @search VARCHAR(10);
SET @search = 'Cat';
WITH T(C)
AS
(
SELECT 'Cat, Dog, Sparrow, Trout, Cow, Seahorse'
)
SELECT *
FROM T
WHERE ', ' + C + ',' LIKE '%, ' + @search + ',%'
Dies erfordert natürlich einen vollständigen Tabellenscan für jede Suche.
In diesem Fall empfiehlt es sich, die Tabelle so zu normalisieren, dass die durch Kommas getrennten Werte in verschiedenen Zeilen angezeigt werden (erste Normalform 1NF) http://en.wikipedia.org/wiki/First_normal_form
Dazu können Sie eine Nizza-Split-Tabellenwertfunktion in SQL implementieren, indem Sie CLR http://bi-tch.blogspot.com/2007/10/sql-clr-net-function-split.html verwenden mit normalem SQL.
CREATE FUNCTION dbo.Split
(
@RowData nvarchar(2000),
@SplitOn nvarchar(5)
)
RETURNS @RtnValue table
(
Id int identity(1,1),
Data nvarchar(100)
)
AS
BEGIN
Declare @Cnt int
Set @Cnt = 1
While (Charindex(@SplitOn,@RowData)>0)
Begin
Insert Into @RtnValue (data)
Select
Data = ltrim(rtrim(Substring(@RowData,1,Charindex(@SplitOn,@RowData)-1)))
Set @RowData = Substring(@RowData,Charindex(@SplitOn,@RowData)+1,len(@RowData))
Set @Cnt = @Cnt + 1
End
Insert Into @RtnValue (data)
Select Data = ltrim(rtrim(@RowData))
Return
END
Dann können Sie die normalisierte Ausgabe mit cross apply
abfragen.
select distinct a.id_column
from MyTable a cross apply
dbo.Split(A.MyCol,',') b
where b.Data='Cat'
Ich habe diese Antwort in einem anderen Forum gefunden, funktioniert einwandfrei ..__ Keine Probleme mit 1 zu finden, wenn es auch eine 10 gibt
WHERE tablename REGEXP "(^|,)@search(,|$)"
select *
from YourTable
where ','+replace(col, ' ', '')+',' like '%,Cat,%'
Ich habe gerade darüber erfahren, als ich nach einer Lösung für ein ähnliches Problem suchte. SQL hat ein neues Schlüsselwort namens CONTAINS, das Sie verwenden können. Weitere Informationen finden Sie unter http://msdn.Microsoft.com/en-us/library/ms187787.aspx
SELECT * FROM TABLE_NAME WHERE
(
LOCATE(',DOG,', CONCAT(',',COLUMN,','))>0 OR
LOCATE(',CAT,', CONCAT(',',COLUMN,','))>0
);
Wenn Sie die IDs und nicht die Zeichenfolgen kennen, gehen Sie folgendermaßen vor:
where mylookuptablecolumn IN (myarrayorcommadelimitedarray)
Stellen Sie nur sicher, dass myarrayorcommadelimitedarray nicht in String-Anführungszeichen gesetzt wird.
funktioniert, wenn Sie A OR B wünschen, aber nicht UND.
Obwohl die knifflige Lösung @ tbaxter120 empfehlenswert ist, aber ich benutze diese Funktion und arbeite wie ein Zauber, pString ist eine begrenzte Zeichenfolge und pDelimiter ist ein Trennzeichen:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[DelimitedSplit]
--===== Define I/O parameters
(@pString NVARCHAR(MAX), @pDelimiter CHAR(1))
RETURNS TABLE WITH SCHEMABINDING AS
RETURN
--===== "Inline" CTE Driven "Tally Table" produces values from 0 up to 10,000...
-- enough to cover VARCHAR(8000)
WITH E1(N) AS (
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
), --10E+1 or 10 rows
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS (--==== This provides the "base" CTE and limits the number of rows right up front
-- for both a performance gain and prevention of accidental "overruns"
SELECT TOP (ISNULL(DATALENGTH(@pString),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
),
cteStart(N1) AS (--==== This returns N+1 (starting position of each "element" just once for each delimiter)
SELECT 1 UNION ALL -- does away with 0 base CTE, and the OR condition in one go!
SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(@pString,t.N,1) = @pDelimiter
),
cteLen(N1,L1) AS(--==== Return start and length (for use in substring)
SELECT s.N1,
---ISNULL(NULLIF(CHARINDEX(@pDelimiter,@pString,s.N1),0)-s.N1,8000)
ISNULL(NULLIF(CHARINDEX(@pDelimiter,@pString,s.N1),0)-s.N1,50000)
FROM cteStart s
)
--===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final element when no delimiter is found.
SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1),
Item = SUBSTRING(@pString, l.N1, l.L1)
FROM cteLen l
;
Dann können Sie es beispielsweise in where-Klausel wie folgt aufrufen:
WHERE [fieldname] IN (SELECT LTRIM(RTRIM(Item)) FROM [dbo].[DelimitedSplit]('2,5,11', ','))
Ich hoffe das hilft.
Der Wert in der Spalte mit durch Kommas getrennten Werten wird mit mehreren durch Kommas getrennten Werten gesucht
declare @d varchar(1000)='-11,-12,10,121'
set @d=replace(@d,',',',%'' or '',''+a+'','' like ''%,')
print @d
declare @d1 varchar(5000)=
'select * from (
select ''1,21,13,12'' as a
union
select ''11,211,131,121''
union
select ''411,211,131,1211'') as t
where '',''+a+'','' like ''%,'[email protected]+ ',%'''
print @d1
exec (@d1)
Da Sie nicht wissen, wie viele durch Kommas getrennte Einträge gefunden werden können, müssen Sie möglicherweise eine Funktion mit SQL Server-Funktionen "charindex" und "substring" erstellen. Die von der Funktion zurückgegebenen Werte können in einem 'in'-Ausdruck verwendet werden.
Ihre Funktion kann rekursiv aufgerufen werden oder Sie können eine Schleife erstellen und nach Einträgen suchen, bis keine weiteren Einträge in der Zeichenfolge vorhanden sind. Bei jedem Aufruf der Funktion wird der zuvor gefundene Index als Ausgangspunkt für den nächsten Aufruf verwendet. Der erste Anruf beginnt bei 0.