Ето малко по-ефективен начин за разделяне на списък от цели числа. Първо създайте таблица с числа, ако все още нямате такава. Това ще създаде таблица със 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, ','));