我有一个SQL函数,我需要将一个ID列表作为字符串传递到:
WHERE ID IN(@MyList)
我环顾四周,大部分答案都是在C#中构建SQL并且循环并调用AddParameter,或者SQL是动态构建的。
我的SQL函数相当大,因此动态构建查询会相当繁琐。
真的没有办法将一串逗号分隔的值传入IN子句吗?
传入的变量表示整数列表,因此它将是:
“1,2,3,4,5,6,7”等
答案 0 :(得分:3)
这是一种分割整数列表的更有效方法。首先,如果您还没有数字表,请创建一个数字表。这将创建一个包含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, ','));
答案 1 :(得分:2)
无法将字符串直接传递到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) )