首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >分组累计求和---极简法

分组累计求和---极简法

原创
作者头像
析言
发布2026-07-20 15:37:42
发布2026-07-20 15:37:42
280
举报
文章被收录于专栏:SQLazySQLazy

问题描述:只保留开票行,金额累计从上次开票开始

有一张业务流水表(包含 ID、Date、Invoiced 和 Amount 四个字段)。每个月有一条记录,其中 Invoiced=1 表示该月开了发票。

现在要输出:每个 ID 下所有开票月份,并且每张发票的金额等于自上个月开票(或开始)到当前月所有金额的总和(包括当前发票本身)。

源数据:

期望结果:只保留开票行,每行 Amount 是自上次开票以来的累计值。

以 AAA 为例:

  • 第一张发票 2023-03:之前有 1 月 (10) + 2 月 (15) + 自身 (15) = 40
  • 第二张发票 2023-06:上次发票之后有 4 月 (10) + 5 月 (10) + 自身 (10) = 30

BBB 同理。

SQLazy 分步实现

下面分别解释一下这些步骤。

第 1 步:按 ID 和日期排序,日期降序

sort id,dt desc

这一步是为了后续分组做准备。降序排列后,一个发票行与它前面的非开票行会先被处理,累计求和时这些行会被归入同一组。

第 2 步:对 invoiced 做累计求和,生成分组号

compute invoiced cum as grp partition id

在每个 ID 分区内,按当前顺序(降序)对 invoiced 进行累计求和(包括当前行)。结果如下:

第 3 步:按 ID 和 grp 分组汇总

summarize dt max as dt invoiced max as invoiced amount sum as amount group id grp

  • dt max:因为降序,每组内日期最大的是开票月份(发票行的日期)。
  • invoiced max:每组至少有一个 invoiced=1,所以最大值是 1。
  • amount sum:累加该组所有金额,即自该发票以来(包括自身)的总和。

第 4 步:选择需要的列

derive id dt invoiced amount

这一步只是清理输出,去掉辅助列 grp。

编译生成 SQL

完成上述步骤后,通过 SQLazy 的编译器可以生成等价的原生 SQL,无需手动编写。

这里生成 MySQL 语句:

代码语言:txt
复制
WITH t3 AS (
  SELECT
    id,
    grp,
    MAX(dt) AS dt,
    MAX(invoiced) AS invoiced,
    SUM(amount) AS amount
  FROM
    (
      SELECT
        id,
        dt,
        invoiced,
        amount,
        SUM(invoiced) OVER (
          PARTITION BY id
          ORDER BY
            CASE
              WHEN id IS NULL THEN 1
              ELSE 0
            END,
            id ASC,
            CASE
              WHEN dt IS NULL THEN 1
              ELSE 0
            END,
            dt DESC ROWS UNBOUNDED PRECEDING
        ) AS grp
      FROM
        invoice
    ) t2
  GROUP BY
    id,
    grp
)
SELECT
  id,
  dt,
  invoiced,
  amount
FROM
  t3
ORDER BY
  id,
  grp

你不需要读懂或调试这段 SQL,只需确认前面四步的逻辑正确,编译器就会输出可运行的代码。

列个表格总结一下:

这个实例展示了 SQLazy 处理“按事件重置的累计”类问题的自然性:通过一个简单的排序技巧加上累计求和,就能把复杂的分组逻辑拆解为清晰的动作。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 问题描述:只保留开票行,金额累计从上次开票开始
  • SQLazy 分步实现
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档