我试图调试别人的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上使用与报表相同的值运行报表查询?


当前回答

表变量

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

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

or

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

其他回答

对于SQL Server 2016+和Azure SQL数据库,添加了STRING_SPLIT函数,这将是这个问题的完美解决方案。以下是文档: https://learn.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

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

我认为MS/SQL有必要在语言中引入一些附加的数据类型。数组是非常常见的,我不明白为什么你不能在存储过程中使用它们。

表变量

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

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

or

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

如果你使用的是字符串列表,SQL中有一个新函数叫做string_split。 Ref Link STRING_SPLIT (Transact-SQL)

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

你可以这样传递这个查询:

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

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

例如:

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

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

Exec (@query)