答案:
您需要使用拆分器拆分存储的序列以获取子字符串和子字符串的顺序。基于 JSON 的方法可能会有所帮助 - 只需将文本转换为有效的 JSON 数组(a~b~c~d~e~f 到 ["a","b","c","d","e","f"]')并使用 OPENJSON() 解析数组。 OPENJSON() 调用的结果是一个包含 key、value 和 type 列的表,如果是 JSON 数组,key 列包含数组中每个项目的从 0 开始的索引:
SELECT c.cid, j.odd, j.even
FROM (VALUES (1, 'a~b~c~d~e~f')) c (cid, applist)
CROSS APPLY (
SELECT
MIN(CASE WHEN CONVERT(int, [key]) % 2 = 0 THEN [value] END) AS [odd],
MIN(CASE WHEN CONVERT(int, [key]) % 2 = 1 THEN [value] END) AS [even]
FROM OPENJSON(CONCAT('["', REPLACE(c.applist, '~', '","'), '"]'))
GROUP BY CONVERT(int, [key]) / 2
) j
结果:
cid odd even
1 a b
1 c d
1 e f
更新:
如果不能选择基于 JSON 的方法,递归 CTE 可能会有所帮助:
CREATE TABLE Candidate (cid int, applist varchar(max))
INSERT INTO Candidate (cid, applist)
VALUES (1, 'a~b~c~d~e~f'), (2, 'g~h~i~i')
;WITH rCTE AS (
SELECT
c.cid,
LEFT(CONCAT(c.applist, '~'), CHARINDEX('~', CONCAT(c.applist, '~')) - 1) AS substring,
STUFF(CONCAT(c.applist, '~'), 1, CHARINDEX('~', CONCAT(c.applist, '~')), '') AS remaining,
0 AS position
FROM Candidate c
UNION ALL
SELECT
r.cid,
LEFT(r.remaining, CHARINDEX('~', r.remaining) - 1),
STUFF(r.remaining, 1, CHARINDEX('~', r.remaining), ''),
r.position + 1
FROM rCTE r
WHERE LEN(r.remaining) > 0
)
SELECT
cid,
MIN(CASE WHEN position % 2 = 0 THEN [substring] END) AS [odd],
MIN(CASE WHEN position % 2 = 1 THEN [substring] END) AS [even]
FROM rCTE
GROUP BY cid, position / 2
OPTION (MAXRECURSION 0);
使用STRING_SPLIT():
请注意,尽管STRING_SPLIT() 是一个选项,但请谨慎使用此功能,因为正如documentation 中所提到的,输出行可能是任何顺序和顺序不保证匹配输入字符串中子字符串的顺序.
SELECT
c.cid,
MIN(CASE WHEN rn % 2 = 0 THEN [value] END) AS [odd],
MIN(CASE WHEN rn % 2 = 1 THEN [value] END) AS [even]
FROM (VALUES
(1, 'a~b~c~d~e~f'),
(2, 'g~h~i~i')
) c (cid, applist)
CROSS APPLY (
SELECT [value], ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 rn
FROM STRING_SPLIT(c.applist, '~')
) s
GROUP BY c.cid, s.rn / 2