2009-11-10 16 views
82

Tengo una consulta de Transact-SQL que usa el operador IN. Algo como esto:Definir variable para usar con el operador IN (T-SQL)

select * from myTable where myColumn in (1,2,3,4) 

¿Hay una manera de definir una variable para contener toda la lista "(1,2,3,4)"? ¿Cómo debería definirlo?

declare @myList {data type} 
set @myList = (1,2,3,4) 
select * from myTable where myColumn in @myList 
+5

Esta pregunta no es igual a la pregunta "Parametrizar una cláusula SQL IN". Esta pregunta se refiere a T-SQL nativo, la otra pregunta se refiere a C#. –

Respuesta

0

Creo que tendrá que declarar una cadena y luego ejecutar esa cadena sql.

Tenga una mirada en Sp_executesql

6

Hay dos maneras de abordar las listas csv dinámicos para las consultas TSQL:

1) Usando un interno de selección

SELECT * FROM myTable WHERE myColumn in (SELECT id FROM myIdTable WHERE id > 10) 

2) El uso de TSQL dinámicamente concatenado

DECLARE @sql varchar(max) 
declare @list varchar(256) 
select @list = '1,2,3' 
SELECT @sql = 'SELECT * FROM myTable WHERE myColumn in (' + @list + ')' 

exec sp_executeSQL @sql 

3) Una posible tercera opción son las variables de tabla. Si tiene SQl Server 2005, puede usar una variable de tabla. Si está en Sql Server 2008, puede incluso pasar variables de tablas enteras como un parámetro a los procedimientos almacenados y usarlos en una unión o como una subselección en la cláusula IN.

DECLARE @list TABLE (Id INT) 

INSERT INTO @list(Id) 
SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 


SELECT 
    * 
FROM 
    myTable 
    JOIN @list l ON myTable.myColumn = l.Id 

SELECT 
    * 
FROM 
    myTable 
WHERE 
    myColumn IN (SELECT Id FROM @list) 
+2

SQL dinámico = evil – badbod99

+0

Usted sabe, existe la palabra clave "set" también ... –

+4

@ badbod99 - Eso es una generalización y todas las generalizaciones son incorrectas :) He ofrecido alternativas –

77
DECLARE @MyList TABLE (Value INT) 
INSERT INTO @MyList VALUES (1) 
INSERT INTO @MyList VALUES (2) 
INSERT INTO @MyList VALUES (3) 
INSERT INTO @MyList VALUES (4) 

SELECT * 
FROM MyTable 
WHERE MyColumn IN (SELECT Value FROM @MyList) 
2

No, no hay tal tipo. Sin embargo, hay algunas opciones:

  • consultas generadas dinámicamente (sp_executesql)
  • Las tablas temporales
  • variables de tipo tabla (lo más parecido que hay a una lista)
  • crear una cadena XML y luego convertir a una tabla con las funciones XML (realmente incómoda y rotunda, a menos que tenga un XML para empezar)

Ninguno de estos son realmente elegantes, pero eso es lo mejor que hay.

7

utilizar una función como esta:

CREATE function [dbo].[list_to_table] (@list varchar(4000)) 
returns @tab table (item varchar(100)) 
begin 

if CHARINDEX(',',@list) = 0 or CHARINDEX(',',@list) is null 
begin 
    insert into @tab (item) values (@list); 
    return; 
end 


declare @c_pos int; 
declare @n_pos int; 
declare @l_pos int; 

set @c_pos = 0; 
set @n_pos = CHARINDEX(',',@list,@c_pos); 

while @n_pos > 0 
begin 
    insert into @tab (item) values (SUBSTRING(@list,@c_pos+1,@n_pos - @c_pos-1)); 
    set @c_pos = @n_pos; 
    set @l_pos = @n_pos; 
    set @n_pos = CHARINDEX(',',@list,@c_pos+1); 
end; 

insert into @tab (item) values (SUBSTRING(@list,@l_pos+1,4000)); 

return; 
end; 

En lugar de utilizar como, haces una unión interna con la tabla devuelta por la función:

select * from table_1 where id in ('a','b','c') 

convierte

select * from table_1 a inner join [dbo].[list_to_table] ('a,b,c') b on (a.id = b.item) 

En una tabla de registro 1M no indexada, la segunda versión tomó la mitad del tiempo ...

aplausos

33
DECLARE @mylist TABLE (Id int) 
INSERT INTO @mylist 
SELECT id FROM (VALUES (1),(2),(3),(4),(5)) AS tbl(id) 

SELECT * FROM Mytable WHERE theColumn IN (select id from @mylist) 
+0

T-SQL dice '[Err] 42000 - [SQL Server] Debe declarar la variable escalar" @mylist ".' –

+0

Solucionado para usted @Paul –

+2

¿Puede simplemente usar' (VALUES (1), (2), (3), (4), (5)) '¿directamente? – toddmo

1

Si usted quiere hacer esto sin necesidad de utilizar una segunda tabla, se puede hacer una comparación LIKE con un REPARTO:

DECLARE @myList varchar(15) 
SET @myList = ',1,2,3,4,' 

SELECT * 
FROM myTable 
WHERE @myList LIKE '%,' + CAST(myColumn AS varchar(15)) + ',%' 

Si el campo que está comparando es ya una cuerda, entonces no necesitarás CAST.

Rodear la coincidencia de columna y cada valor único en comas garantizará una coincidencia exacta. De lo contrario, un valor de 1 se encontraría en una lista que contiene '4,2,15,'

0
DECLARE @StatusList varchar(MAX); 
SET @StatusList='1,2,3,4'; 
DECLARE @Status SYS_INTEGERS; 
INSERT INTO @Status 
SELECT Value 
FROM dbo.SYS_SPLITTOINTEGERS_FN(@StatusList, ','); 
SELECT Value From @Status; 
+2

¡será una mejor respuesta si describes tu código allí! – Deep

3
DECLARE @myList TABLE (Id BIGINT) INSERT INTO @myList(Id) VALUES (1),(2),(3),(4); 
select * from myTable where myColumn in(select Id from @myList) 

Tenga en cuenta que para una lista larga o sistemas de producción no se recomienda el uso de esta forma, ya que puede ser mucho más lento que el operador simple IN como someColumnName in (1,2,3,4) (probado usando 8000+ lista de elementos)

Cuestiones relacionadas