2009-11-10 6 views
82

J'ai une requête Transact-SQL qui utilise l'opérateur IN. Quelque chose comme ceci:Définir la variable à utiliser avec l'opérateur IN (T-SQL)

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

est-il un moyen de définir une variable pour tenir la liste entière « (1,2,3,4) »? Comment devrais-je le définir?

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

Cette question n'est pas la même que la question "Parameterize an SQL IN clause". Cette question fait référence à T-SQL natif, l'autre question à C#. –

Répondre

0

Je pense que vous devrez déclarer une chaîne et ensuite exécuter cette chaîne sql.

Jetez un oeil à sp_executesql

6

Il y a deux façons d'aborder les listes de csv dynamiques pour les requêtes TSQL:

1) Utilisation d'une sélection interne

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

2) En utilisant TSQL dynamiquement concaténé

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) Une troisième option possible est les variables de table. Si vous avez SQl Server 2005, vous pouvez utiliser une variable de table. Si vous êtes sur Sql Server 2008, vous pouvez même passer des variables de table entières en tant que paramètre aux procédures stockées et les utiliser dans une jointure ou en tant que sous-sélection dans la clause 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

Dynamique SQL = mal – badbod99

+0

Vous savez, il y a aussi le mot clé "set" ... –

+4

@ badbod99 - C'est une généralisation et toutes les généralisations sont fausses :) J'ai proposé des alternatives –

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

Non, il n'y a pas ce type. Mais il y a des choix:

  • requêtes générées dynamiquement (sp_executesql)
  • tables temporaires
  • des variables de type tableau (chose la plus proche qu'il ya une liste)
  • Créer une chaîne XML et ensuite convertir à une table avec les fonctions XML (vraiment gênant et rond-point, sauf si vous avez un XML pour commencer)

Aucune d'elles n'est vraiment élégante, mais c'est la meilleure.

7

Utilisez une fonction comme ceci:

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; 

Au lieu d'utiliser comme, vous faites une jointure avec la table retournée par la fonction:

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

devient

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

Dans une table d'enregistrement 1M non indexée, la deuxième version a pris environ la moitié du temps ...

acclamations

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 dit '[Err] 42000 - [SQL Server] Doit déclarer la variable scalaire" @mylist ".' –

+0

Fixé pour vous @Paul –

+2

Pouvez-vous juste utiliser' (VALUES (1), (2), (3), (4), (5)) 'directement? – toddmo

1

Si vous voulez faire cela sans l'aide d'une seconde table, vous pouvez faire une comparaison LIKE CAST:

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

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

Si le champ que vous comparez est déjà une chaîne alors vous n'aurez pas besoin de CAST. Entourer à la fois la correspondance de colonne et chaque valeur unique en virgules assurera une correspondance exacte. Dans le cas contraire, une valeur de 1 se trouve dans une liste contenant «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

ce sera une meilleure réponse si vous décrivez votre code là-bas! – 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) 

S'il vous plaît noter que pour une liste ou des systèmes de production, il est recommandé de ne pas utiliser cette façon comme peut être beaucoup plus lent qu'un simple IN opérateur comme someColumnName in (1,2,3,4) (testé en utilisant la liste des éléments 8000+)

Questions connexes