2009-06-23 84 views
6

Tengo una consulta SQL básica, a partir de:¿Cómo uso una lista de valores separados por comas como filtro en T-SQL?

SELECT top 20 application_id, [name], location_id FROM apps 

Ahora, me gustaría terminarlo de manera que no presente (escrito en Pseudocódigo)

if @lid > 0 then 
    WHERE location_id IN (@lid) 
else 
    WHERE location_id is all values in location_id column 

a lo solicitado, Aquí hay un ejemplo

application_id    name    location_id 
---------------------------------------------------------- 
1       Joe Blogs   33 
2       Sam Smith   234 
3       Jeremy Carr  33 

@locid son los resultados dados por el usuario, por ejemplo ' 33, 234 '

Si @lid está vacío, me gustaría que muestre todas las filas para location_id con name y application_id. De lo contrario, me gustaría que todas las filas de salida en relación con los números proporcionados en @lid (que significa location_id

lo tanto, si @lid es 0:.

application_id    name    location_id 
---------------------------------------------------------- 
1       Joe Blogs   33 
2       Sam Smith   234 
3       Jeremy Carr  33 

De lo contrario, si contiene @lid '33'

application_id    name    location_id 
---------------------------------------------------------- 
1       Joe Blogs   33 
3       Jeremy Carr  33 
+0

¿Podrían presentar algunos datos de la muestra y de resultados deseado? – Quassnoi

+0

Espero que esto sea suficiente para ti. Gracias por adelantado. –

Respuesta

3

Pruebe usar Caso, que sirve para un operador IIF o un operador ternario. Por favor verifique en este enlace http://msdn.microsoft.com/en-us/library/ms181765.aspx

aplausos

+0

He intentado con el caso, pero con resultados mixtos. ¿Podría proporcionar algún código de muestra que pueda probar en comparación con mis ejemplos? –

+0

CASO CUANDO myNum <10 ENTONCES 'Pequeño' ELSE 'Big' FIN –

2

Ver esta entrada en mi blog:

Si su @lid es una lista separada por comas de los números enteros, utilice esto:

WITH cd AS 
     (
     SELECT 1 AS first, CHARINDEX(',', @lid, 1) AS next 
     UNION ALL 
     SELECT next + 1, CHARINDEX(',', @lid, next + 1) 
     FROM cd 
     WHERE next > 0 
     ), 
     lid AS 
     (
     SELECT CAST(SUBSTRING(@lid, first, CASE next WHEN 0 THEN LEN(@lid) + 1 ELSE next END - first)AS INT) AS id 
     FROM cd 
     ) 
SELECT d.* 
FROM (
     SELECT DISTINCT id 
     FROM lid 
     ) l 
JOIN apps a 
ON  a.location_id = l.id 
     AND @lid <> '0' 
UNION ALL 
SELECT * 
FROM apps a 
WHERE @lid = '0' 

Esto es mucho más eficiente que el uso OR construcciones.

+0

Mi objetivo es devolver todas las filas en la columna location_id si no hay nada en @lid, por lo que produciría el mismo tipo de resultados que "SELECT location_id from inquiries". Si no hay nada en @lid, quiero que busque cada location_id en la base de datos. –

+0

Eliminé mi respuesta y le di +1 después de algunos puntos de referencia en la construcción OR con algunos conjuntos de datos más grandes. Nunca hice clic para ver cuán ineficientes son (solo se usan en conjuntos de datos más pequeños). De todos modos, creo que la última consulta es lo que el OP está buscando. – Eric

+0

@Eric: gracias. Sí, SQL Server no puede optimizar el pozo de quirófano. Sin embargo, su consulta funcionaría bien en MySQL: notaría que @lid no es cero y eliminaría completamente el predicado del plan. – Quassnoi

0

Usted realmente no necesita el operador ternario para esto:

SELECT top 20 application_id, [name], location_id 
FROM apps 
WHERE (@lid > 0 AND location_id IN (@lid)) OR @lid <= 0 
+0

¿Cómo se "location_id EN (@lid)" trabajo sin SQL dinámico? – gbn

+0

¿Pensé que @lid era un INT? –

+0

Hubo una actualización pregunta donde está ahora ... CSV – gbn

0

que están pidiendo diferentes preguntas aquí. Esta es la respuesta a su pregunta original (sobre el operador ternario, pero como se puede ver, no se necesita nada como un operador ternario para esto):

SELECT top 20 application_id, [name], location_id 
FROM apps 
WHERE @lid = 0 OR location_id IN (@lid) 

Pero eso era antes de que sabía que @lid era varchar y podría contener diferentes valores separados por comas.

Bueno, esto (aproximadamente del csv) es otra cuestión que se haya solicitado antes aquí:

Passing an "in" list via stored procedure
T-SQL stored procedure that accepts multiple Id values

+0

¿Cómo se "location_id EN (@lid)" trabajo sin SQL dinámico? – gbn

+0

@gbn: esto no tiene nada que ver con la cuestión que nos ocupa, que es aproximadamente un operador ternario (que tampoco es lo que se necesita aquí, pero eso es otra vez otro discution ;-). – fretje

3

Si @locid es una lista por ejemplo, "33, 234", etc, entonces no hay la solución aquí funcionará. Sin embargo, supongo que estos fueron publicados antes de su actualización con esta información.

que suponer que porque usted dijo esto:

@locid es los resultados dados por el usuario, por ejemplo '33, 234'

No se puede ampliar la variable de manera directa que location_in IN (33, 234). En realidad, está pidiendo location_id = '33, 234', que fallará con una conversión CAST, debido a la precedencia del tipo de datos.

Tiene que analizar la lista primero en forma de tabla para usar en una construcción JOIN/EXISTS. Hay varias opciones y Erland las cubre todas aquí: Arrays and Lists in SQL Server 2005

+0

Tiene razón, y ya he analizado esta "lista" varchar para que compruebe todos los valores, como una forma de usar valores múltiples en una declaración select. –

0

Lo siguiente debe ser el truco para usted.

DECLARE @lid SMALLINT

SET @lid = 0

SELECT TOP 20 application_id, [nombre], LOCATION_ID

de las aplicaciones

DONDE ((@lid> 0 y location_id = @lid)

OR (@lid = 0 AND location_id > @lid)) 

Si @lid = 0, devolverá TODO filas IF @lid tiene un valor particular, solo se devuelve la fila para ese valor @lid.

0

Si bien no es exactamente una mejor práctica usar 1 = 1, aquí funciona el truco.

SELECT top 20 application_id, [name], location_id FROM apps 
WHERE 
    (@lid > 0 and @lid = location_id) 
or 
    (isnull(@lid, 0) <= 0 and 1=1) 
1

Una forma es dividir la cadena en las comas, quitar los espacios e insertar los valores en una tabla temporal. Entonces puede unir su consulta a la tabla temporal.

Este es un fragmento de código de T-SQL que divide una lista separada por comas e inserta los miembros en una tabla temporal. Una vez que haya poblado la tabla, puede unirse contra ella.

-- This bit splits up a comma separated list of key columns 
-- and inserts them in order into a table. 
-- 
if object_id ('tempdb..#KeyCols') is not null 
    drop table #KeyCols 

create table #KeyCols (
     ,KeyCol   nvarchar (100) 
) 

set @comma_pos = 0 
set @len = len(@KeyCols) 
while @len > 0 begin 
    set @comma_pos = charindex(',', @KeyCols) 
    if @comma_pos = 0 begin 
     set @KeyCol = @KeyCols 
     set @KeyCols = '' 
    end else begin 
     set @KeyCol = left (@KeyCols, @comma_pos - 1) 
     set @KeyCols = substring(@KeyCols, 
           @comma_pos + 1, 
           len (@KeyCols) - @comma_pos) 
    end 
    insert #KeyCols (KeyCol) 
    values (@KeyCol) 
    set @len = len (@KeyCols) 
end 
+0

+1, una técnica útil. ¿Alguna razón para no ir solo con una tabla temporal en memoria? – CRice

+0

No particularmente, si recuerdo correctamente el sproc que originalmente provenía de la vida establecida en SQL Server 2000. Podría usar una variable de tabla con la misma facilidad en las versiones modernas de SQL Server. – ConcernedOfTunbridgeWells

+0

Ok, es bueno saberlo. Prefiero la alternativa en memoria. – CRice

2

Suponiendo @locid & @lid son la misma , voy a utilizar @locid ... La siguiente iba a funcionar. Lo he dividido para que se vea bien en SO.

SELECT application_id, [name], location_id 
FROM apps 
WHERE 
    ( 
    @locid = 0 
    OR 
    CHARINDEX 
    ( 
     ',' + CAST(location_id AS VARCHAR(50)) + ',' 
     , 
     ',' + @locid + ',' 
     , 
     0 
    ) > 0 
) 
+0

¿cómo puedo recortar espacios adicionales pasados ​​en CSV? –

2
WHERE CHARINDEX(LocationId, @lid) > 1 
+0

Debería explicar mejor su respuesta. –

Cuestiones relacionadas