Ответ 1
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)
У меня есть запрос Transact-SQL, который использует оператор IN. Что-то вроде этого:
select * from myTable where myColumn in (1,2,3,4)
Есть ли способ определить переменную для хранения всего списка "(1,2,3,4)"? Как его определить?
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)
Существует два способа решения динамических списков CSV для запросов TSQL:
1) Используя внутренний выбор
SELECT * FROM myTable WHERE myColumn in (SELECT id FROM myIdTable WHERE id > 10)
2) Использование динамически объединенного TSQL
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) Возможный третий вариант - это переменные таблицы. Если у вас есть SQl Server 2005, вы можете использовать переменную таблицы. Если на Sql Server 2008 вы даже можете передавать целые переменные таблицы в качестве параметра хранимых процедур и использовать его в соединении или в качестве подзадача в предложении 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)
Используйте такую функцию:
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;
Вместо того, чтобы использовать подобное, вы делаете внутреннее соединение с таблицей, возвращаемой функцией:
select * from table_1 where id in ('a','b','c')
становится
select * from table_1 a inner join [dbo].[list_to_table] ('a,b,c') b on (a.id = b.item)
В неиндексированной таблице записей 1М вторая версия заняла около половины времени...
веселит
DECLARE @myList TABLE (Id BIGINT) INSERT INTO @myList(Id) VALUES (1),(2),(3),(4);
select * from myTable where myColumn in(select Id from @myList)
Обратите внимание, что для длинного списка или производственных систем не рекомендуется использовать этот способ, так как он может быть намного медленнее, чем простой оператор IN
например someColumnName in (1,2,3,4)
(протестировано с использованием списка элементов 8000+)
Нет, такого типа нет. Но есть несколько вариантов:
Ни один из них не очень изящный, но лучший из них.
Если вы хотите сделать это без использования второй таблицы, вы можете сделать LIKE-сравнение с CAST:
DECLARE @myList varchar(15)
SET @myList = ',1,2,3,4,'
SELECT *
FROM myTable
WHERE @myList LIKE '%,' + CAST(myColumn AS varchar(15)) + ',%'
Если поле, которое вы сравниваете, уже является строкой, вам не нужно CAST.
Окружение как совпадения столбцов, так и каждого уникального значения в запятых гарантирует точное совпадение. В противном случае значение 1 будет найдено в списке, содержащем ', 4,2,15,'
небольшое улучшение в @LukeH, нет необходимости повторять "INSERT INTO": и ответ @realPT - нет необходимости иметь SELECT:
DECLARE @MyList TABLE (Value INT)
INSERT INTO @MyList VALUES (1),(2),(3),(4)
SELECT * FROM MyTable
WHERE MyColumn IN (SELECT Value FROM @MyList)
Я знаю, что это старый, но TSQL => 2016, вы можете использовать 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)
Начиная с SQL2017, вы можете использовать STRING_SPLIT и сделать это:
declare @myList nvarchar(MAX)
set @myList = '1,2,3,4'
select * from myTable where myColumn in (select value from STRING_SPLIT(@myList,','))
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;
Как никто не упоминал ранее, начиная с Sql Server 2016, вы также можете использовать массивы json и 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)
Вы можете проверить это в sql fiddle demo
Вы также можете проще охватить более сложные случаи с помощью json - см. Поиск списка значений и диапазона в SQL с помощью предложения WHERE IN с переменной SQL?
Я думаю, вам придется объявить строку и затем выполнить эту строку SQL.
Посмотрите на sp_executeSQL