首页 > 解决方案 > 将奇数行和偶数行显示为 2 个单独的列

问题描述

但给定的要求是:

a~b~c~d~e~f

和 O/p 像:

 a b
 c d 
 e f

这里a,e是奇数值,c是偶数值。所以我尝试使用这个查询string_split()来分隔这个符号'~'。有人可以帮忙吗?

在这个查询中,我没有得到奇怪的偶数列输出:

select 
   C.CID, c.nunique, 
   Row Number() OVER (ORDER BY C.CID) as RowNum,
   CASE 
      WHEN (ROW Number () OVER(ORDER BY c.CID)) % 2 = 0 THEN s.value 
      WHEN (Row Number() OVER (ORDER BY c.CID)) % 2 = 1 THEN s.value
      ELSE " invalid"
   END
from Candidate c
cross apply STRING SPLIT(applist,~) s

标签: sqlsql-servertsqlsplitcase

解决方案


回答:

您需要使用拆分器拆分存储的序列以获取子字符串和子字符串的顺序。基于 JSON 的方法在这里可能会有所帮助 - 只需将文本转换为有效的 JSON 数组 ( a~b~c~d~e~finto ["a","b","c","d","e","f"]') 并使用OPENJSON(). 调用的结果OPENJSON()是一个带有 columns 的表,key如果是 JSON 数组,该列包含数组中每个项目的从 0 开始的索引:valuetypekey

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()是一个选项,但请谨慎使用此函数,因为如文档所述,输出行可能是任何顺序,并且不能保证该顺序与输入字符串中子字符串的顺序相匹配

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

推荐阅读