【问题标题】:Group by column. If null, group by other column MySQL按列分组。如果为 null,则按 MySQL 的其他列分组
【发布时间】:2021-06-03 09:41:15
【问题描述】:

我有这个问题:

SELECT 
 vcl.id,
     vcl.batch_id,
     vcl.type,
     vcl.amount,
     vcl.date
FROM vrcorporateledger vcl
LEFT JOIN payroll_list pl ON pl.id = vcl.batch_id

给出以下输出:

每当 col 类型中有“CREDIT”时,我想将运行余额增加 col 数量的值;每当col类型中有“DEBIT”时,我想在按batch_id col分组后将累积余额减少col金额的值。所以预期的结果是:

1000-2+5-4-49=950。

如果可能的话,我还想创建一个“余额”列,在每个点/步骤中,我都会看到结果余额。

预期输出如下:

【问题讨论】:

  • 基本上和以前一样的建议

标签: mysql sql group-by case


【解决方案1】:

我认为您正在寻找SQL Window functions。它们基本上允许您“在分区上”进行聚合。

附带说明:这是计算运行平衡的一种非常糟糕的方法。

我强烈建议在运行时将余额存储在单独的列中。这应该允许您:

  • 即使行被更改或删除,也要进行严格检查
  • 拥有数百万条记录时的正常速度

【讨论】:

    【解决方案2】:
    WITH cte AS (
    SELECT type,
           SUM(amount) OVER (PARTITION BY CASE type WHEN 'CREDIT' THEN RAND()
                                                    WHEN 'DEBIT' THEN batchID
                                                    ELSE 0 END ) amount,
           MIN(`date`) OVER (PARTITION BY CASE type WHEN 'CREDIT' THEN RAND()
                                                    WHEN 'DEBIT' THEN batchID
                                                    ELSE 0 END ) `date`,
           SUM(CASE type WHEN 'CREDIT' THEN amount
                         WHEN 'DEBIT' THEN -amount
                         ELSE 0 END) OVER (ORDER BY `date`) balance,
           batchID,
           LEAD(batchID) OVER (ORDER BY `date`) next_batchID
    FROM source_data
    )
    SELECT type, 
           amount, 
           balance, 
           `date`
    FROM cte
    WHERE CASE WHEN batchID = next_batchID THEN 0 ELSE 1 END
    

    https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=75255728f6d64a91a2ebf62edc2d0a0b

    【讨论】:

      【解决方案3】:

      如果你的 MySQL 版本是 8 或以上,那么你可以使用带有窗口函数的公用表表达式,如下所示:

      架构 (MySQL v8.0)

      create table vrcorporateledger (id int,batch_id int,type varchar(10),amount float,Tdate timestamp);
      
      insert into vrcorporateledger  values (1,null,'CREDIT',1000,'2021/03/04 06:19:00');
      insert into vrcorporateledger  values (2,1,'DEBIT',1,'2021/03/04 07:00:19');
      insert into vrcorporateledger  values (3,1,'DEBIT',1,'2021/03/04 07:00:25');
      insert into vrcorporateledger  values (4,null,'CREDIT',5,'2021/03/05 06:19:00');
      insert into vrcorporateledger  values (5,2,'DEBIT',1,'2021/03/04 08:58:10');
      insert into vrcorporateledger  values (6,2,'DEBIT',3,'2021/03/04 08:58:16');
      insert into vrcorporateledger  values (7,null,'DEBIT',49,'2021/03/04 16:42:33');
      

      查询 #1

      WITH cte AS (
      SELECT id,type,
             (case when batch_id is null then (case when type='DEBIT' then -amount else amount end) else 
             SUM(case when type='DEBIT' then -amount else amount end) OVER (PARTITION BY batch_id)end) amount,
             (case when batch_id is null then Tdate else
             MIN(Tdate) OVER (PARTITION BY batch_id ) end) Trandate,       
             batch_id,
             LEAD(batch_id) OVER (ORDER BY id) next_batch
             
      FROM vrcorporateledger
      )
      SELECT type, 
             amount, 
             sum(amount)over(order by id) running_balance,       
             Trandate date
      FROM cte
      WHERE  batch_id is null or batch_id =next_batch
      order by id;
      
      type amount date running_balance
      CREDIT 1000 2021-03-04 06:19:00 1000
      DEBIT -2 2021-03-04 07:00:19 998
      CREDIT 5 2021-03-05 06:19:00 1003
      DEBIT -4 2021-03-04 08:58:10 999
      DEBIT -49 2021-03-04 16:42:33 950

      View on DB Fiddle

      【讨论】:

        猜你喜欢
        • 2015-05-18
        • 1970-01-01
        • 2011-01-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多