SQLazy:按条件分段累计
问题描述
按条件分段累计,遇到 logic 为 t 时重置累计值并重新开始累加。一张事件表 table_t1 记录了事件序列,包含 id(排序序号)、logic(条件标记,取值为 t 或 f)、val(数值)三个字段。现在要新增计算列 output:当 logic 等于 t 时,output 置为 1;否则 output 等于上一行的 output 加上当前行的 val,
源数据
id |
logic |
val |
1 |
t |
1 |
2 |
f |
2 |
3 |
f |
3 |
4 |
f |
4 |
5 |
t |
0 |
6 |
f |
1 |
7 |
f |
2 |
期望结果
id |
logic |
val |
output |
1 |
t |
1 |
1 |
2 |
f |
2 |
3 |
3 |
f |
3 |
6 |
4 |
f |
4 |
10 |
5 |
t |
0 |
1 |
6 |
f |
1 |
2 |
7 |
f |
2 |
4 |
id=1(logic=t):新段起点,output = 1
id=2 至 id=4(logic=f):在同一段内按行累计,output = 上一行 output + 当前行 val,得到 3、6、10
id=5(logic=t):遇到重置条件,此时新开一段,output = 1
SQLazy 分步实现
核心思路:先生成分组标记再分区累计。先通过计算列生成一个逻辑分组标记(logic_run),该标记在每次遇到 logic 为 t 时递增,从而将数据划分为多个独立的段。然后以 logic_run 为分区键,在每个分区内用累计功能(cum)对条件表达式进行累计运算,实现对 output 的分段累计。
Name |
Anchor |
Statement |
t2 |
t1 |
sort id asc |
t3 |
compute if (logic = 't' then 1 else 0) cum as logic_run |
|
result |
compute if (logic = 't' then 1 else val) cum as op partition logic_run |
下面逐一解释这些步骤。
第 1 步:按 id 升序排序
sort id asc
将数据按 id 升序排列,确保记录按事件发生的先后顺序处理,这是后续分段和累计的前提。

第 2 步:创建逻辑分组标记
compute if (logic = 't' then 1 else 0) cum as logic_run
这是最关键的一步。用计算列功能配合跨行参数 cum(累计),对条件式 if (logic='t' then 1 else 0) 进行累计求和。当 logic 为 t 时贡献值 1(表示新段的开始),为 f 时贡献值 0(延续当前段)。累计结果 logic_run 的值在每次遇到 t 时递增 1,从而将原始数据划分为多个分段组:前 4 条记录(id=1-4)的 logic_run=1,后 3 条记录(id=5-7)的 logic_run=2。

第 3 步:按分区累计计算 output
compute if (logic = 't' then 1 else val) cum as op partition logic_run
在 logic_run 分区内,用累计(cum)功能对条件式 if (logic='t' then 1 else val) 进行累计求和。每个分区独立计算:当 logic 为 t 时累计值重置为 1,为 f 时累计上一行的累计值加上当前行的 val。partition logic_run 确保分区之间的累计互不影响。这样就实现了按条件分段累计的效果。

后面可以用 derive 功能删掉多余的字段。
编译生成 SQL
确认上述 3 步逻辑后,SQLazy 编译器自动生成原生 SQL(这里是 MySQL 语法):
WITH t3 AS (
SELECT id, logic, val, SUM(CASE
WHEN logic = 't' THEN 1
ELSE 0
END) OVER (ORDER BY CASE
WHEN id IS NULL THEN 1
ELSE 0
END, id ASC ROWS UNBOUNDED PRECEDING) AS logic_run
FROM t2
)
SELECT id, logic, val, logic_run
, SUM(CASE
WHEN logic = 't' THEN 1
ELSE val
END) OVER (PARTITION BY logic_run ORDER BY CASE
WHEN id IS NULL THEN 1
ELSE 0
END, id ASC ROWS UNBOUNDED PRECEDING) AS oput
FROM t3
ORDER BY CASE
WHEN id IS NULL THEN 1
ELSE 0
END, id ASC
SQLazy 让你用业务语言描述逻辑,而不是用 SQL 语法写嵌套查询。这个例子体现了 SQLazy 的两大特色:一是分步计算,将条件重置累计拆解为排序、生成分组标记、分区累计三个独立步骤,每步可独立验证;二是 partition + cum 的分区累计语法,相比 SQL 的窗口函数写法更简洁直观,直接用业务逻辑描述“遇到 t 就重置、否则累加”的语义。
官方链接
SQLazy 在线体验:sqlazy.com(免费,无需注册)
SQLazy 项目仓库:github.com/SPLWare/SQLazy

英文版 https://c.esproc.com/article/1783563563174