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 升序排列,确保记录按事件发生的先后顺序处理,这是后续分段和累计的前提。

Picture2png

第 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。


Picture3png

第 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 确保分区之间的累计互不影响。这样就实现了按条件分段累计的效果。

Picture4png

后面可以用 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