【问题标题】:why is this query skipping on STRING_SPLIT为什么此查询在 STRING_SPLIT 上跳过
【发布时间】:2019-09-19 19:44:24
【问题描述】:

我正在尝试将 GLACCTNBR 列上的数据之一拆分为多个列,但某些记录未正确拆分并最终得到 Null 值。

WITH C AS(
      SELECT distinct  
      m.ACCTID
      ,m.ITEMDESC
      ,m.GLACCTNBR
      ,m.TOTAL
      ,m.DEPFILENBR
      ,m.DEPFILESEQ
      ,m.ITEMACCTID
      ,m.AMOUNT
      ,value 
      ,ROW_NUMBER() OVER(PARTITION BY m.GLACCTNBR ORDER BY (SELECT 1)) as rn
     FROM TG_ITEM_DATA m 
     inner join TG_TRAN_DATA t on m.DEPFILENBR = t.DEPFILENBR 
     AND m.DEPFILESEQ = t.DEPFILESEQ 
     AND m.EVENTNBR = t.EVENTNBR 
     AND m.TRANNBR = t.TRANNBR 
     AND t.VOIDDT IS NULL 
     AND NOT(t.ITEMIND='T') 
     AND m.GLACCTNBR IS NOT NULL 
     CROSS APPLY STRING_SPLIT(m.GLACCTNBR, '|') AS BK
     WHERE ( 

    (m.DEPFILENBR=2019261 AND m.DEPFILESEQ=1)) 
     AND m.ACCTID IS NOT NULL
)
SELECT distinct depfilenbr, depfileseq,acctid,GLACCTNBR,ITEMACCTID,AMOUNT,
      [1] AS PLUDEP
      ,[2] AS FUND
      ,[3] AS REVCD
      ,[4] AS SUBREVCD
      ,[5] AS BALSJT

FROM C
PIVOT(
    max(VALUE)
    FOR RN IN([1],[2],[3],[4],[5])  
) as PVT

GROUP BY DEPFILENBR,depfileseq,acctid,GLACCTNBR,ITEMACCTID,AMOUNT,[1],[2],[3],[4],[5]
depfilenbr  depfileseq  acctid  GLACCTNBR           ITEMACCTID  AMOUNT  PLUDEP  FUND    REVCD   SUBREVCD    BALSJT
2019261              1  5053    08|48R|3800|00|0000 50-0028      38.41      08   48R     3800         00      0000
2019261              1  5053    08|48R|3896|00|0000 50-001           0    NULL  NULL     NULL       NULL      NULL

【问题讨论】:

  • 你知道哪些记录返回空值吗?
  • 澄清一下:您知道导致 NULL 的记录的实际值吗?例如,如果 GLACCTNBR 的项目多于或少于五个,则可能导致 NULL。换句话说,你说,“一些记录没有被正确分割”——哪些记录?那些价值是什么?尝试只在 CTE 中运行查询...
  • 在我的回答中,您会发现使用 v2016+ 进行拆分的更好方法。只是为了回答你的问题:这条线ROW_NUMBER() OVER(PARTITION BY m.GLACCTNBR ORDER BY (SELECT 1)) 无论如何都是一个hack,如果在另一行中有另一个GLACCTNBR 具有相同的值,它将意外返回。您可能会使用其他分区条件 (PARTITION BY mACCTID,m.GLACCTNBR ???)
  • @AlanBurstein,我刚刚找到了一种使用 JSON-splitting in a type-safe way 的简单方法(更新 2 部分)。可能对你来说很有趣...

标签: tsql split pivot pivot-table common-table-expression


【解决方案1】:

始终值得一提的是,在任何情况下都应避免使用分隔数据。它违反了 1.NF 并且在查询中是真正的痛苦。如果有机会在输入端改变这个问题,你应该先这样做。

由于您使用的是STRING_SPLIT(),因此您必须使用 v2016+。

比这个不返回片段位置并且不保证按预期顺序返回的怪异STRING_SPLIT()好多了,是JSON的一个技巧:

DECLARE  @SomeDelimitedString VARCHAR(100)='part1|part2|part3';

DECLARE @JsonArray NVARCHAR(MAX)=CONCAT('["',REPLACE(@SomeDelimitedString,'|','","'),'"]');

SELECT @SomeDelimitedString          AS TheOriginal
      ,@JsonArray                    AS TransformedToJSON
      ,JSON_VALUE(@JsonArray,'$[0]') AS TheFirstFragment
      ,JSON_VALUE(@JsonArray,'$[1]') AS TheSecondFragment
      ,JSON_VALUE(@JsonArray,'$[2]') AS TheThirdFragment

结果

part1|part2|part3   ["part1","part2","part3"]   part1   part2   part3

简而言之:

我们使用一些简单的字符串操作将分隔字符串转换为 JSON 数组。现在我们可以使用 JsonPath 通过它的位置来抓取片段。

You might read this answer for more details(用于 v2016+ 的 UPDATE 部分和用于类型安全结果的 UPDATE 2 部分)。

我无法对此进行测试,但您可以尝试以下方法:

  SELECT   
   m.ACCTID
  ,m.ITEMDESC
  ,m.GLACCTNBR
  ,m.TOTAL
  ,m.DEPFILENBR
  ,m.DEPFILESEQ
  ,m.ITEMACCTID
  ,m.AMOUNT
  ,JSON_VALUE(JsonArray,'$[0]') AS PLUDEP 
  ,JSON_VALUE(JsonArray,'$[1]') AS FUND 
  ,JSON_VALUE(JsonArray,'$[2]') AS REVCD 
  ,JSON_VALUE(JsonArray,'$[3]') AS SUBREVCD 
  ,JSON_VALUE(JsonArray,'$[4]') AS BALSJT 
 FROM TG_ITEM_DATA m 
 inner join TG_TRAN_DATA t on m.DEPFILENBR = t.DEPFILENBR 
 AND m.DEPFILESEQ = t.DEPFILESEQ 
 AND m.EVENTNBR = t.EVENTNBR 
 AND m.TRANNBR = t.TRANNBR 
 AND t.VOIDDT IS NULL 
 AND NOT(t.ITEMIND='T') 
 AND m.GLACCTNBR IS NOT NULL 
 CROSS APPLY (SELECT CONCAT('["',REPLACE(m.GLACCTNBR,'|','","'),'"]')) BK(JsonArray)
 WHERE m.DEPFILENBR=2019261 
   AND m.DEPFILESEQ=1 
   AND m.ACCTID IS NOT NULL
--GROUP BY m.DEPFILENBR,m.depfileseq,m.acctid,m.GLACCTNBR,m.ITEMACCTID,m.AMOUNT,PLUDEP,FUND,REVCD,SUBREVCD,BALSJT

【讨论】:

    猜你喜欢
    • 2011-02-16
    • 1970-01-01
    • 2011-12-15
    • 1970-01-01
    • 1970-01-01
    • 2021-09-18
    • 2021-10-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多