Если вам нужно сделать это как набор, а не по одной строке за раз. Учитывая следующую функцию разбиения:
USE tempdb;
GO
CREATE FUNCTION dbo.SplitStrings(@List NVARCHAR(MAX))
RETURNS TABLE
AS
RETURN ( SELECT Item FROM
( SELECT Item = x.i.value('(./text())[1]', 'nvarchar(max)')
FROM ( SELECT [XML] = CONVERT(XML, '<i>'
+ REPLACE(@List,',', '</i><i>') + '</i>').query('.')
) AS a CROSS APPLY [XML].nodes('i') AS x(i) ) AS y
WHERE Item IS NOT NULL
);
GO
Затем, используя следующую таблицу, примеры данных и строковую переменную, вы можете получить все результаты следующим образом:
DECLARE @foo TABLE(ID INT IDENTITY(1,1), col NVARCHAR(MAX));
INSERT @foo(col) SELECT N'c,d,e,f,g';
INSERT @foo(col) SELECT N'c,e,b';
INSERT @foo(col) SELECT N'd,e,f,x,a,e';
DECLARE @string NVARCHAR(MAX) = N'a,b,c,d';
;WITH x AS
(
SELECT f.ID, c.Item FROM @foo AS f
CROSS APPLY dbo.SplitStrings(f.col) AS c
), y AS
(
SELECT ID, Item FROM x
UNION
SELECT x.ID, s.Item
FROM dbo.SplitStrings(@string) AS s
CROSS JOIN x
)
SELECT DISTINCT ID, Items = STUFF((SELECT ',' + Item
FROM y AS y2 WHERE y2.ID = y.ID
FOR XML PATH(''), TYPE).value('.[1]', 'nvarchar(max)'), 1, 1, N'')
FROM y;
Результаты:
ID Items
-- ----------
1 a,b,c,d,e,f,g
2 a,b,c,d,e
3 a,b,c,d,e,f,x
Теперь, когда все сказали, что вы действительно должны сделать, это следовать предыдущему совету и сохранить эти вещи в связанной таблице в первую очередь. Вы можете использовать методологию разделения одного и того же типа для хранения строк по отдельности всякий раз, когда происходит вставка или обновление, вместо того, чтобы просто выгружать CSV в один столбец, и вашим приложениям на самом деле не нужно менять способ передачи данных в ваши процедуры. Но, конечно, будет проще получить данные!
EDIT
Добавление потенциального решения для SQL Server 2008, которое немного более замысловатое, но позволяет добиться цели с помощью одного меньшего цикла (с использованием масштабного сканирования и замены таблиц). Я не думаю, что это лучше, чем решение, описанное выше, и, конечно, оно менее ремонтопригодно, но это вариант для тестирования, если вы обнаружите, что можете перейти на версию 2008 года или лучше (а также для любых пользователей старше 2008 года, которые наткнулся на этот вопрос).
SET NOCOUNT ON;
-- let's pretend this is our static table:
CREATE TABLE #x
(
ID INT IDENTITY(1,1),
col NVARCHAR(MAX)
);
INSERT #x(col) VALUES(N'c,d,e,f,g'), (N'c,e,b'), (N'd,e,f,x,a,e');
-- and here is our parameter:
DECLARE @string NVARCHAR(MAX) = N'a,b,c,d';
код:
DECLARE @sql NVARCHAR(MAX) = N'DECLARE @src TABLE(ID INT, col NVARCHAR(32));
DECLARE @dest TABLE(ID INT, col NVARCHAR(32));';
SELECT @sql += '
INSERT @src VALUES(' + RTRIM(ID) + ','''
+ REPLACE(col, ',', '''),(' + RTRIM(ID) + ',''') + ''');'
FROM #x;
SELECT @sql += '
INSERT @dest VALUES(' + RTRIM(ID) + ','''
+ REPLACE(@string, ',', '''),(' + RTRIM(ID) + ',''') + ''');'
FROM #x;
SELECT @sql += '
WITH x AS (SELECT ID, col FROM @src UNION SELECT ID, col FROM @dest)
SELECT DISTINCT ID, Items = STUFF((SELECT '','' + col
FROM x AS x2 WHERE x2.ID = x.ID FOR XML PATH('''')), 1, 1, N'''')
FROM x;'
EXEC sp_executesql @sql;
GO
DROP TABLE #x;
Это гораздо сложнее сделать в 2005 году (хотя и не невозможно), потому что вам нужно изменить предложения VALUES()
на UNION ALL
...