J'ai une requête Transact-SQL qui utilise l'opérateur IN. Quelque chose comme ça:
select * from myTable where myColumn in (1,2,3,4)
Y at-il un moyen de définir une variable pour contenir la liste complète "(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
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)
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)
Utilisez une fonction comme celle-ci:
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 like, vous créez une jointure interne avec la table renvoyé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 seconde version prenait environ la moitié du temps ...
à votre santé
Il existe deux manières de traiter les listes de fichiers csv dynamiques pour les requêtes TSQL:
1) Utiliser un select interne
SELECT * FROM myTable WHERE myColumn in (SELECT id FROM myIdTable WHERE id > 10)
2) Utilisation de TSQL concaténé dynamiquement
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 utilisez SQL Server 2008, vous pouvez même transmettre des variables de table entières en tant que paramètre aux procédures stockées et les utiliser dans une jointure ou comme 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)
DECLARE @myList TABLE (Id BIGINT) INSERT INTO @myList(Id) VALUES (1),(2),(3),(4);
select * from myTable where myColumn in(select Id from @myList)
Veuillez noter que pour les systèmes de longue liste ou de production, il est déconseillé d'utiliser cette méthode, car elle peut être beaucoup plus lente que IN
operator comme someColumnName in (1,2,3,4)
(testé avec une liste de plus de 8 000 éléments)
Non, il n'y a pas un tel type. Mais il y a quelques choix:
Aucune d'entre elles n'est vraiment élégante, mais c'est la meilleure qui soit.
légère amélioration sur @LukeH, il n'y a pas besoin de répéter les réponses "INSERT INTO": et @ realPT - pas besoin d'avoir le SELECT:
DECLARE @MyList TABLE (Value INT)
INSERT INTO @MyList VALUES (1),(2),(3),(4)
SELECT * FROM MyTable
WHERE MyColumn IN (SELECT Value FROM @MyList)
Je sais que c'est vieux maintenant mais TSQL => 2016, vous pouvez utiliser STRING_SPLIT:
DECLARE @InList varchar(255) = 'This;Is;My;List';
WITH InList (Item) AS (
SELECT value FROM STRING_SPLIT(@InList, ';')
)
SELECT *
FROM [Table]
WHERE [Item] IN (SELECT Tag FROM InList)
À partir de SQL2017, vous pouvez utiliser STRING_SPLIT et procédez comme suit:
declare @myList nvarchar(MAX)
set @myList = '1,2,3,4'
select * from myTable where myColumn in (select value from STRING_SPLIT(@myList,','))
Si vous voulez faire cela sans utiliser une seconde table, vous pouvez faire une comparaison avec LIKE avec un 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, vous n'avez pas besoin de CAST.
Entourer à la fois la correspondance de colonne et chaque valeur unique entre virgules assurera une correspondance exacte. Sinon, une valeur de 1 serait trouvée dans une liste contenant ', 4,2,15,'
Comme personne ne l’a mentionné auparavant, à partir de Sql Server 2016, vous pouvez également utiliser des tableaux json et OPENJSON (Transact-SQL)
:
declare @filter nvarchar(max) = '[1,2]'
select *
from dbo.Test as t
where
exists (select * from openjson(@filter) as tt where tt.[value] = t.id)
Vous pouvez le tester dans sql fiddle demo
Vous pouvez également couvrir plus facilement des cas plus complexes avec JSON - voir Liste de recherche de valeurs et plage en SQL à l'aide de la clause WHERE IN avec une variable SQL?
Je pense que vous devrez déclarer une chaîne, puis exécuter cette chaîne SQL.
Regardez sp_ExecuteSQL
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;