【问题标题】:String Aggregration字符串聚合
【发布时间】:2020-12-17 13:08:22
【问题描述】:

我的源表如下所示:

Account_Number, Code, Transaction_Amount, Comment, Sequence_Number
4321, W, 10.21,,1
4321, C,,'Payment',2
4321, C,,'From Checking Account',3
4321, D,20.00,,4
4321, C,,'Direct Deposit',4
7430, W, 40.00,,5
7430, C,,'From Checking',5

来源是一个交易账本,W代表“提款”,D代表“存款”,C代表评论。当每笔交易发生时,它都可以跟进。 0 个或更多注释行。 我想汇总“W”或“D”之后的所有 cmets,并将它们添加到“W”或“D”行。示例:

Account_Number, Code, Transaction_Amount, Comment, Sequence_Number
4321, W, 10.21,'Payment,From Checking Account',1
4321, D,20.00,'Direct Deposit',4
7430, W, 40.00,"From Checking,5

【问题讨论】:

  • 您使用的是哪个 SQL Server 版本?
  • 为什么最后两行和前两行的序号相同?

标签: sql sql-server window-functions gaps-and-islands string-aggregation


【解决方案1】:

这是使用LEADSTRING_AGG 的查询。假设WithdrawDeposit 行的最后一个数字很大,Account_Number

HERE 是工作代码。

SELECT *
    ,(
        SELECT STRING_AGG(comm.Comment, ', ') Comment
        FROM Transactions comm
        WHERE comm.Account_Number = a.Account_Number
            AND comm.Code = 'C'
            AND comm.Sequence_Number >= a.Sequence_Number
            AND comm.Sequence_Number < a.END_Sequence_Number
        )
FROM (
    SELECT *
        ,ISNULL(LEAD(Sequence_Number) OVER (
                PARTITION BY Account_Number ORDER BY Sequence_Number
                ), 100000000) END_Sequence_Number
    FROM dbo.Transactions t
    WHERE Code IN ('W', 'D')
    ) a

结果:

【讨论】:

  • 你可以从上面的查询中选择你想要的columns
【解决方案2】:

我会使用string_agg() 来做到这一点,但通过为每一行分配组。什么是组?非 C 代码的累积数量。所以:

select account,
       max(case when code <> 'C' then code end) as code,
       sum(amount) as amount,
       string_agg(comment, ',') within group (order by seq) as comments
from (select t.*,
             sum(case when code <> 'C' then 1 else 0 end) over (partition by account order by sequence) as grp
      from t
     ) t
group by account, grp;

【讨论】:

  • 谢谢大家的回复,你们太棒了!!!!!
  • @user2274800 。 . .作为 OP,您应该接受您认为最合适的答案。
  • @user2274800 。 . .你点击答案左上角的“接受”。
【解决方案3】:

我将此理解为一个间隙和岛屿问题,您希望在其中收集每个间隙中的所有 cmets,并将它们带到前一个岛屿。

SQL Server 没有用于字符串聚合的窗口函数,这让事情变得有点棘手。这可能是横向连接的更简单地址:

select t.account_number, t.code, t.transaction_amount, c.comment, t.sequence_number
from mytable t
outer apply (
    select top (1) t1.sequence_number as next_sequence_number
    from mytable t1
    where 
        t1.account_number = t.account_number 
        and t1.sequence_number > t.sequence_number
        and t1.code <> 'C' 
    order by t1.sequence_number
) s
outer apply (
    select string_agg(t1.comment) within group(order by t1.sequence_number) comment
    from mytable t1
    where
        t1.account_number = t.account_number 
        and t1.sequence_number > t.sequence_number
        and (
            t1.sequence_number < s.next_sequence_number 
            or s.next_sequence_number is null
        )
        and t1.code = 'C' 
) c
where t.code <> 'C'

第一个横向连接计算“下一个”非注释事务的序列号;第二个聚合当前行和下一行之间的所有 cmets。

请注意,string_agg() 仅从 SQL Server 2017 开始可用。

【讨论】:

  • 我忘了提到我们在 Azure(托管实例)上使用 SQL Server 19。我相信他们有 LEAD , LAG 和 STRING_AGG 功能,如果事务后只有评论,我可以轻松做到,但源表的结构可能有一个或几行 cmets。我可以
  • @user2274800:好的,所以你的 SQL Server 版本有string_agg() - 上面的查询应该做你想做的事。
猜你喜欢
  • 2013-07-04
  • 2017-09-14
  • 2020-07-21
  • 1970-01-01
  • 2023-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多