221

我正在尝试调试其他人的 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 上使用与报告相同的值运行报告查询?

4

8 回答 8

287

表变量

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
于 2013-08-22T06:01:07.207 回答
42

假设变量类似于:

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);
于 2015-10-16T13:11:39.973 回答
24

你是对的,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);
于 2013-08-22T05:35:17.283 回答
8

对于 SQL Server 2016+ 和 Azure SQL 数据库,添加了 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

于 2017-10-25T21:33:34.213 回答
6

最后我得出的结论是,如果不修改查询的工作方式,我就无法将值存储在变量中。我使用 SQL 分析器来捕获这些值,然后将它们硬编码到查询中以查看它是如何工作的。这些整数数组中有 18 个,其中一些包含 30 多个元素。

我认为 MS/SQL 需要在语言中引入一些额外的数据类型。数组很常见,我不明白为什么不能在存储过程中使用它们。

于 2013-08-27T01:25:17.067 回答
3

我用这个:

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)
于 2019-07-08T13:08:00.293 回答
3

string_split如果您使用的是字符串列表,则会调用 SQL 中的一个新函数。参考链接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) <> ''))
于 2018-11-13T22:53:28.247 回答
2

您不能这样做,但您可以执行将其存储在变量中的整个查询。

例如:

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

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

Exec (@query)
于 2013-08-22T05:36:18.627 回答