sql - una - Donde el valor en la columna contiene valores delimitados por comas
sql contar registros repetidos (13)
Hola, me pregunto cómo escribir una declaración SQL para SQL Server 2008 que selecciona entradas donde una columna contiene un valor, ahora el valor dentro de la columna es una lista delimitada por comas (por lo general, solo podría haber una entrada (y ninguna coma inicial) ) Entonces, ¿qué está comprobando "es este valor contenido en algún lugar dentro de la lista?", por ejemplo:
COLUMN = Cat, Dog, Sparrow, Trout, Cow, Seahorse
Does COLUMN contain Cat? YES
Does COLUMN contain horse? NO
Does COLUMN contain Sheep? NO
o
COLUMN = Mouse
Does COLUMN contain Hare? NO
Does COLUMN contain Mouse? YES
etc
Estaba pensando que podría usar la palabra clave ''IN'' como tal
SELECT id_column FROM table_name WHERE ''Cat'' IN COLUMN
pero esto no funciona, ya que parece que solo puede usar eso para verificar si una columna contiene uno de una serie de valores delimitados por comas.
Tampoco puedo usar CONTAINS () O ''LIKE'' como este, en el ejemplo anterior devolvería valores para ''horse'' ya que toda la cadena contiene horse en ''Seahorse'', y no puedo buscar la aguja más una coma (si Estoy buscando ''caballo'', la búsqueda sería ''caballo'', ¿y qué pasa si la entrada está al final de la lista? Y no puedo buscar una coma más una aguja (si estoy buscando ''caballo'' la búsqueda sería '', caballo'') como si la entrada es la primera en la lista? Y no puedo usar ambos como ¿qué pasa si la entrada es la única entrada (única)?
Gracias por la ayuda que cualquiera pueda aportar.
Aclamaciones.
Acabo de enterarme de esto cuando estaba buscando una solución a un problema similar. SQL tiene una nueva palabra clave llamada CONTAINS que puede usar. Para obtener más detalles, consulte http://msdn.microsoft.com/en-us/library/ms187787.aspx
Aunque la solución difícil @ tbaxter120 recomendada es buena, pero utilizo esta función y trabajo como un encanto, pString es una cadena delimitada y pDelimiter es un carácter delimitador:
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
;
Entonces, por ejemplo, puede invocarlo en la cláusula where, como se muestra a continuación:
WHERE [fieldname] IN (SELECT LTRIM(RTRIM(Item)) FROM [dbo].[DelimitedSplit](''2,5,11'', '',''))
Espero que esto ayude.
Como no sabe cuántas entradas delimitadas por comas puede encontrar, puede que necesite crear una función con las funciones ''charindex'' y ''substring'' de SQL Server. Los valores, tal como los devuelve la función, se pueden usar en una expresión ''in''.
Su función puede invocarse recursivamente o puede crear un bucle, buscando entradas hasta que no haya más entradas presentes en la cadena. Cada llamada a la función utiliza el índice encontrado previamente como punto de partida de la próxima llamada. La primera llamada comienza en 0.
Donde el valor en la columna que contiene valores delimitados por comas busca con múltiples comas delimitadas
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 ''''%,''+@d+ '',%''''''
print @d1
exec (@d1)
Encontré esta respuesta en otro foro, funciona perfecto. No hay problemas para encontrar 1 si también hay un 10
WHERE tablename REGEXP "(^|,)@search(,|$)"
Hay un escenario complicado. Si estoy buscando ''40'' en la lista ''17, 34,400,12 '', entonces encontraría ", 40" y devolvería esa entrada incorrecta. Esto se ocupa de todas las soluciones:
WHERE ('','' + RTRIM(MyColumn) + '','') LIKE ''%,'' + @search + '',%''
La mejor solución en este caso es normalizar su tabla para tener los valores separados por comas en diferentes filas (Primera forma normal 1NF) http://en.wikipedia.org/wiki/First_normal_form
Para eso, puede implementar una buena función de tabla dividida en SQL, usando CLR http://bi-tch.blogspot.com/2007/10/sql-clr-net-function-split.html o usando SQL simple.
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
Luego puede consultar la salida normalizada utilizando cross apply
select distinct a.id_column
from MyTable a cross apply
dbo.Split(A.MyCol,'','') b
where b.Data=''Cat''
Si conoce las identificaciones en lugar de las cadenas, use este enfoque:
where mylookuptablecolumn IN (myarrayorcommadelimitedarray)
Solo asegúrese de que myarrayorcommadelimitedarray no esté entre comillas de cadena.
funciona si quieres A o B, pero no AND.
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 + '',%''
Por supuesto, esto requerirá un escaneo de tabla completo para cada búsqueda.
SELECT * FROM TABLENAME WHERE FIND_IN_SET(@search, column)
Si resulta que su columna tiene espacios en blanco entre los elementos de la lista, use
SELECT * FROM TABLENAME WHERE FIND_IN_SET(@search, REPLACE(column, '' '', ''''))
http://dev.mysql.com/doc/refman/5.0/en/string-functions.html
SELECT * FROM TABLE_NAME WHERE
(
LOCATE('',DOG,'', CONCAT('','',COLUMN,'',''))>0 OR
LOCATE('',CAT,'', CONCAT('','',COLUMN,'',''))>0
);
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 YourTable
where '',''+replace(col, '' '', '''')+'','' like ''%,Cat,%''