这是适用于 SQL Server 2008 及更高版本的解决方案。
它基于 XML 和 XQuery。
使用 XQuery 的 FLWOR 表达式可以标记奇数和偶数 XML 元素。剩下的只是几个 REPLACE() 函数调用来组成所需的输出。
SQL
-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, tokens VARCHAR(1024));
INSERT INTO @tbl (tokens) VALUES
('Peter,John:Ryan,Jack:Evans,Chris'),
('Peter,John:Ryan,Jack'),
('Hank,Tom'),
(''),
('Cruise,Tom');
-- DDL and sample data population, end
DECLARE @separator CHAR(1) = ':'
, @comma CHAR(1) = ',';
SELECT ID, tokens
, REPLACE(REPLACE(c.query('
for $x in /root/r[position() mod 2 eq 0]
let $pos := count(root/r[. << $x])
return concat($x, sql:variable("@comma"), (/root/r[$pos])[1])
').value('text()[1]', 'VARCHAR(8000)')
, SPACE(1), @separator), @comma, SPACE(1)) AS result
FROM @tbl
CROSS APPLY (SELECT CAST('<root><r><![CDATA[' +
REPLACE(REPLACE(tokens,@comma,@separator), @separator, ']]></r><r><![CDATA[') +
']]></r></root>' AS XML)) AS t1(c)
ORDER BY ID;
输出
+----+----------------------------------+----------------------------------+
| ID | tokens | result |
+----+----------------------------------+----------------------------------+
| 1 | Peter,John:Ryan,Jack:Evans,Chris | John Peter:Jack Ryan:Chris Evans |
| 2 | Peter,John:Ryan,Jack | John Peter:Jack Ryan |
| 3 | Hank,Tom | Tom Hank |
| 4 | | NULL |
| 5 | Cruise,Tom | Tom Cruise |
+----+----------------------------------+----------------------------------+
SQL #2(不要尝试,它不会起作用)
不幸的是,SQL Server 甚至不完全支持 XQuery 1.0 标准。 XQuery 3.1 是最新的标准。 XQuery 1.0 函数 fn:substring-after() 和 fn:substring-before() 严重缺失。
在梦境中,解决方案会简单得多,如下所示:
SELECT *
, c.query('
for $x in /root/r
return concat(fn:substring-after($x, ","), ",", fn:substring-before($x, ","))
')
FROM @tbl
CROSS APPLY (SELECT TRY_CAST('<root><r><![CDATA[' +
REPLACE(tokens, @separator, ']]></r><r><![CDATA[') +
']]></r></root>' AS XML)) AS t1(c);
请投票支持以下改进 SQL Server 的建议:
SQL Server vNext (post 2019) and NoSQL functionality
它成为 SQL Server 最流行的请求之一。
目前的投票总数为 590,而且还在增加。