【问题标题】:display odd and even rows into 2 separate columns将奇数行和偶数行显示为 2 个单独的列
【发布时间】:2021-12-11 18:05:09
【问题描述】:

但给定的要求是:

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

【问题讨论】:

  • 我无法理解您想要什么。你能粘贴一个输入数据和结果的例子吗?
  • 不幸的是STRING_SPLIT 可以以任何顺序返回子字符串。最好的选择是递归 cte。

标签: sql sql-server tsql split case


【解决方案1】:

答案:

您需要使用拆分器拆分存储的序列以获取子字符串和子字符串的顺序。基于 JSON 的方法可能会有所帮助 - 只需将文本转换为有效的 JSON 数组(a~b~c~d~e~f["a","b","c","d","e","f"]')并使用 OPENJSON() 解析数组。 OPENJSON() 调用的结果是一个包含 keyvaluetype 列的表,如果是 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

【讨论】:

  • 感谢您的回答!它真的很有帮助,你展示的输出是完美的..但我的要求是在不使用 OpenJson() 的情况下解决
  • 非常感谢您解释这 3 种不同的方法来解决我的问题... CTE 方法帮助我获得了更多的分数。
猜你喜欢
  • 2019-01-02
  • 1970-01-01
  • 1970-01-01
  • 2012-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多