可能重复:
参数化 SQL IN 子句?
我有一个 SQL 函数,我需要将一个 ID 列表作为字符串传递到:
身份在哪里(@MyList)
我环顾四周,大多数答案要么是在 C# 中构建 SQL 并且它们循环并调用 AddParameter,要么是动态构建 SQL。
我的 SQL 函数相当大,因此动态构建查询会相当乏味。
真的没有办法将一串逗号分隔的值传递到 IN 子句中吗?
我传入的变量表示整数列表,因此它将是:
“1,2,3,4,5,6,7”等
可能重复:
参数化 SQL IN 子句?
我有一个 SQL 函数,我需要将一个 ID 列表作为字符串传递到:
身份在哪里(@MyList)
我环顾四周,大多数答案要么是在 C# 中构建 SQL 并且它们循环并调用 AddParameter,要么是动态构建 SQL。
我的 SQL 函数相当大,因此动态构建查询会相当乏味。
真的没有办法将一串逗号分隔的值传递到 IN 子句中吗?
我传入的变量表示整数列表,因此它将是:
“1,2,3,4,5,6,7”等
这是一种更有效的拆分整数列表的方法。首先,创建一个数字表,如果您还没有的话。这将创建一个包含 100,000 个唯一整数的表(您可能需要更多或更少):
;WITH x AS
(
SELECT TOP (1000000) Number = ROW_NUMBER() OVER
(ORDER BY s1.[object_id])
FROM sys.all_objects AS s1 CROSS JOIN sys.all_objects AS s2
ORDER BY s1.[object_id]
)
SELECT Number INTO dbo.Numbers FROM x;
CREATE UNIQUE CLUSTERED INDEX n ON dbo.Numbers(Number);
然后是一个函数:
CREATE FUNCTION [dbo].[SplitInts_Numbers]
(
@List NVARCHAR(MAX),
@Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
SELECT Item = CONVERT(INT, SUBSTRING(@List, Number,
CHARINDEX(@Delimiter, @List + @Delimiter, Number) - Number))
FROM dbo.Numbers
WHERE Number <= CONVERT(INT, LEN(@List))
AND SUBSTRING(@Delimiter + @List, Number, 1) = @Delimiter
);
您可以在此处将性能与迭代方法进行比较:
http://sqlfiddle.com/#!3/960d2/1
为了避免使用数字表,您还可以尝试使用基于 XML 的函数版本 - 它更紧凑但效率较低:
CREATE FUNCTION [dbo].[SplitInts_XML]
(
@List VARCHAR(MAX),
@Delimiter CHAR(1)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN ( SELECT Item = CONVERT(INT, Item) FROM (
SELECT Item = x.i.value('(./text())[1]', 'int') FROM (
SELECT [XML] = CONVERT(XML, '<i>' + REPLACE(@List, @Delimiter, '</i><i>')
+ '</i>').query('.') ) AS a CROSS APPLY [XML].nodes('i') AS x(i)) AS y
WHERE Item IS NOT NULL
);
无论如何,一旦你有了一个函数,你可以简单地说:
WHERE ID IN (SELECT Item FROM dbo.SplitInts_Numbers(@MyList, ','));
IN
无法将字符串直接传递到子句中。但是,如果您将列表作为字符串提供给存储过程,例如,您可以使用以下脏方法。
首先,创建这个函数:
CREATE FUNCTION [dbo].[fnNTextToIntTable] (@Data NTEXT)
RETURNS
@IntTable TABLE ([Value] INT NULL)
AS
BEGIN
DECLARE @Ptr int, @Length int, @v nchar, @vv nvarchar(10)
SELECT @Length = (DATALENGTH(@Data) / 2) + 1, @Ptr = 1
WHILE (@Ptr < @Length)
BEGIN
SET @v = SUBSTRING(@Data, @Ptr, 1)
IF @v = ','
BEGIN
INSERT INTO @IntTable (Value) VALUES (CAST(@vv AS int))
SET @vv = NULL
END
ELSE
BEGIN
SET @vv = ISNULL(@vv, '') + @v
END
SET @Ptr = @Ptr + 1
END
-- If the last number was not followed by a comma, add it to the result set
IF @vv IS NOT NULL
INSERT INTO @IntTable (Value) VALUES (CAST(@vv AS int))
RETURN
END
(注意:这不是我的原始代码,但由于我工作地点的版本控制系统,我丢失了链接到源代码的标题注释。)
然后像这样使用它:
SELECT *
FROM tblMyTable
INNER JOIN fnNTextToIntTable(@MyList) AS List ON tblMyTable.ID = List.Value
或者,如您的问题所示:
SELECT *
FROM tblMyTable
WHERE ID IN ( SELECT Value FROM fnNTextToIntTable(@MyList) )