2009-11-10 12 views
82

Ho una query Transact-SQL che utilizza l'operatore IN. Qualcosa di simile a questo:Definire la variabile da utilizzare con l'operatore IN (T-SQL)

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

C'è un modo per definire una variabile per contenere l'intero elenco "(1,2,3,4)"? Come dovrei definirlo?

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

Questa domanda non è la stessa della domanda "Parametrizzare una clausola SQL IN". Questa domanda si riferisce al T-SQL nativo, l'altra domanda si riferisce a C#. –

risposta

0

Penso che dovrai dichiarare una stringa e quindi eseguire quella stringa sql.

Dai un'occhiata alla sp_executesql

6

Ci sono due modi per affrontare liste csv dinamici per le query TSQL:

1) con un interno di selezione

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

2) Uso di TSQL concatenato in modo dinamico

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 possibile terza opzione è le variabili di tabella. Se hai SQl Server 2005 puoi usare una variabile di tabella. Se su Sql Server 2008 è anche possibile passare intere variabili di tabella come parametro alle stored procedure e utilizzarlo in un join o come sottoselezione nella clausola 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 dinamico = diabolico – badbod99

+0

Sai, c'è anche la parola chiave "set" ... –

+4

@ badbod99 - Questa è una generalizzazione e tutte le generalizzazioni sono sbagliate :) Ho offerto delle alternative –

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, non c'è questo tipo. Ma ci sono alcune scelte:

  • query generate dinamicamente (sp_executesql)
  • tabelle temporanee
  • variabili di tipo tabella (cosa più vicina che c'è da una lista)
  • Creare una stringa XML e poi convertire a una tabella con le funzioni XML (davvero imbarazzante e rotonda, a meno che non si abbia un XML per iniziare)

Nessuno di questi è davvero elegante, ma quello è il meglio che c'è.

7

Utilizzare una funzione come questa:

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; 

Invece di usare come, si effettua un inner join con la tabella restituita dalla funzione:

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

diventa

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

In una tabella di record 1M non indicativa, la seconda versione ha impiegato circa la metà del tempo ...

applausi

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] Deve dichiarare la variabile scalare" @milista ".' –

+0

Risolto il problema per te @Paul –

+2

Puoi semplicemente usare' (VALUES (1), (2), (3), (4), (5)) 'direttamente? – toddmo

1

Se si vuole fare questo senza usare una seconda tabella, si può fare un confronto omogeneo con un cast:

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

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

Se il campo si sta confrontando è già una stringa quindi non sarà necessario CAST.

Circondare sia la corrispondenza della colonna che ogni singolo valore in virgola garantiranno una corrispondenza esatta. In caso contrario, un valore pari a 1 sarebbe stato trovato in un elenco contenente '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

sarà una risposta migliore se descrivi il tuo codice lì! – 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) 

prega di notare che per la lunga lista o sistemi di produzione non è consigliabile utilizzare in questo modo in quanto potrebbe essere molto più lento di un semplice operatore IN come someColumnName in (1,2,3,4) (testato utilizzando un elenco di elementi 8000+)

Problemi correlati