Переменная SQL для хранения списка целых чисел

Я пытаюсь отладить другие отчеты SQL и поместил запрос базовых отчетов в окна запросов SQL 2012.

Один из параметров, который запрашивает отчет, - это список целых чисел. Это достигается в отчете через раскрывающийся список с несколькими выборами. В основе запроса запроса используется этот целочисленный список в предложении where, например.

select *
from TabA
where TabA.ID in (@listOfIDs)

Я не хочу изменять запрос, который я отлаживаю, но я не могу понять, как создать переменную на SQL Server, которая может хранить этот тип данных для проверки.

например.

declare @listOfIDs int
set listOfIDs  = 1,2,3,4

Нет типа данных, который может содержать список целых чисел, поэтому как я могу запустить запрос отчета на моем SQL Server с теми же значениями, что и отчет?

Ответ 1

Таблица переменной

declare @listOfIDs table (id int);
insert @listOfIDs(id) values(1),(2),(3);    

select *
from TabA
where TabA.ID in (select id from @listOfIDs)

или

declare @listOfIDs varchar(1000);
SET @listOfIDs = ',1,2,3,'; --in this solution need put coma on begin and end

select *
from TabA
where charindex(',' + CAST(TabA.ID as nvarchar(20)) + ',', @listOfIDs) > 0

Ответ 2

Предполагая, что переменная похожа на:

CREATE TYPE [dbo].[IntList] AS TABLE(
[Value] [int] NOT NULL
)

И хранимая процедура использует его в этой форме:

ALTER Procedure [dbo].[GetFooByIds]
    @Ids [IntList] ReadOnly
As 

Вы можете создать IntList и вызвать процедуру следующим образом:

Declare @IDs IntList;
Insert Into @IDs Select Id From dbo.{TableThatHasIds}
Where Id In (111, 222, 333, 444)
Exec [dbo].[GetFooByIds] @IDs

Или, если вы предоставляете IntList самостоятельно

DECLARE @listOfIDs dbo.IntList
INSERT INTO @listofIDs VALUES (1),(35),(118);

Ответ 3

Вы правы, в SQL-Server нет типа данных, который может содержать список целых чисел. Но вы можете сохранить список целых чисел в виде строки.

DECLARE @listOfIDs varchar(8000);
SET @listOfIDs = '1,2,3,4';

Затем вы можете разбить строку на отдельные целочисленные значения и поместить их в таблицу. Ваша процедура может уже сделать это.

Вы также можете использовать динамический запрос для достижения того же результата:

DECLARE @SQL nvarchar(8000);

SET @SQL = 'SELECT * FROM TabA WHERE TabA.ID IN (' + @listOfIDs + ')';
EXECUTE (@SQL);

Ответ 4

Для SQL Server 2016+ и базы данных SQL Azure была добавлена функция STRING_SPLIT, которая была бы идеальным решением для этой проблемы. Вот документация: https://docs.microsoft.com/en-us/sql/t-sql/functions/string-split-transact-sql

Вот пример:

/*List of ids in a comma delimited string
  Note: the ') WAITFOR DELAY ''00:00:02''' is a way to verify that your script 
        doesn't allow for SQL injection*/
DECLARE @listOfIds VARCHAR(MAX) = '1,3,a,10.1,) WAITFOR DELAY ''00:00:02''';

--Make sure the temp table was dropped before trying to create it
IF OBJECT_ID('tempdb..#MyTable') IS NOT NULL DROP TABLE #MyTable;

--Create example reference table
CREATE TABLE #MyTable
([Id] INT NOT NULL);

--Populate the reference table
DECLARE @i INT = 1;
WHILE(@i <= 10)
BEGIN
    INSERT INTO #MyTable
    SELECT @i;

    SET @i = @i + 1;
END

/*Find all the values
  Note: I silently ignore the values that are not integers*/
SELECT t.[Id]
FROM #MyTable as t
    INNER JOIN 
        (SELECT value as [Id] 
        FROM STRING_SPLIT(@listOfIds, ',')
        WHERE ISNUMERIC(value) = 1 /*Make sure it is numeric*/
            AND ROUND(value,0) = value /*Make sure it is an integer*/) as ids
    ON t.[Id] = ids.[Id];

--Clean-up
DROP TABLE #MyTable;

Результат запроса 1,3

~ Приветствия

Ответ 5

В конце я пришел к выводу, что без изменения того, как работает запрос, я не мог хранить значения в переменных. Я использовал профилировщик SQL, чтобы поймать значения, а затем жестко закодировал их в запросе, чтобы увидеть, как он работает. Было 18 из этих целых массивов, а в некоторых из них было более 30 элементов.

Я думаю, что MS/SQL необходимо ввести некоторые дополнительные типы данных в язык. Массивы довольно распространены, и я не понимаю, почему вы не могли использовать их в хранимой процедуре.

Ответ 6

Вы не можете сделать это так, но вы можете выполнить весь запрос, сохраняя его в переменной.

Например:

DECLARE @listOfIDs NVARCHAR(MAX) = 
    '1,2,3'

DECLARE @query NVARCHAR(MAX) = 
    'Select *
     From TabA
     Where TabA.ID in (' + @listOfIDs + ')'

Exec (@query)

Ответ 7

В SQL есть новая функция, называемая string_split если вы используете список строк. Ссылка ссылки STRING_SPLIT (Transact-SQL)

DECLARE @tags NVARCHAR(400) = 'clothing,road,,touring,bike'
SELECT value
FROM STRING_SPLIT(@tags, ',')
WHERE RTRIM(value) <> '';

Вы можете передать этот запрос с in следующим образом:

SELECT *
  FROM [dbo].[yourTable]
  WHERE (strval IN (SELECT value FROM STRING_SPLIT(@tags, ',') WHERE RTRIM(value) <> ''))

Ответ 8

Я использую это:

1-Объявите переменную временной таблицы в скрипте вашего здания:

DECLARE @ShiftPeriodList TABLE(id INT NOT NULL);

2-Распределить во временную таблицу:

IF (SOME CONDITION) 
BEGIN 
        INSERT INTO @ShiftPeriodList SELECT ShiftId FROM [hr].[tbl_WorkShift]
END
IF (SOME CONDITION2)
BEGIN
    INSERT INTO @ShiftPeriodList
        SELECT  ws.ShiftId
        FROM [hr].[tbl_WorkShift] ws
        WHERE ws.WorkShift = 'Weekend(VSD)' OR ws.WorkShift = 'Weekend(SDL)'

END

3-Ссылка на таблицу, когда вам это нужно в выражении WHERE:

INSERT INTO SomeTable WHERE ShiftPeriod IN (SELECT * FROM @ShiftPeriodList)