怎样用 esProc 实现连续区间的差集运算

某数据库有两个表,原库存表 data_add 存储了多个物品的多批库存,每批库存有一个起始编号 START_NUM 和一个终止编号 END_NUM,表示区间范围。

ID

ITEM_ID

START_NUM

END_NUM

1

337

101

400

2

337

500

800

3

337

801

1200

4

337

1500

1600

5

337

15000

16000

6

337

20000

30000

7

444

20

30

消耗表 data_cons 存储了多个物品的多批消耗,每批消耗同样是个区间范围。

ID

ITEM_ID

START_NUM

END_NUM

1

337

240

300

2

337

301

400

3

337

850

1100

4

337

1500

1510

5

337

15000

16000

现在要计算出每个物品的现库存,即原库存的多段区间和消耗的多段区间的差集,结果用多段区间来表示。原库存的区间可能被消耗成不连续的多段区间,这种情况下要自然生成多条记录,每条记录对应一个区间,比如原库存的区间 [500:1200] 被消耗成了 2 个区间 [500:849] 和[1101:1200]。

ITEM_ID

START_NUM

END_NUM

337

101

239

337

500

849

337

1101

1200

337

1511

1600

337

20000

30000

444

20

30

SQL无法用变量表示集合,不方便进行集合的集合之间的运算,代码非常繁琐。SPL 可以用变量代表集合,容易表达各类集合运算:https://try.esproc.com/splx?3xM


 A

B

1

$select * from data_add.txt

$select * from data_cons.txt

2

=A1.group(ITEM_ID;~.conj(to(START_NUM,END_NUM)):a)

=B1.group(ITEM_ID;~.conj(to(START_NUM,END_NUM)):b)

3

=A2.join(ITEM_ID,B2,b)

4

=A3.derive([a, b].merge@d().group@i(~!=~[-1]+1):diff)

5

=A4.news(diff; ITEM_ID, ~1:START_NUM, ~.m(-1):END_NUM)

A1-B1:加载数据。

A2:用 group 函数对原库存按物品分类,但不汇总,将组内的每个区间转为一个连续序列的小集合,再合并为一个大集合。~ 表示当前组,函数 to 可按起止序号生成连续序列。

Picture1png
B2:对消耗表进行相同的处理。

Picture2png
A3=A2.join(ITEM_ID,B2,b):用 join 函数按物品编号进行左关联。

Picture3png
A4=A3.derive([a, b].merge@d()…..)。新增计算列,先将每个物品的原库存集合和消耗集合进行差集计算。函数 merge 对有序集合进行归并,@d 表示计算差集。注意差集后的序列不连续,比如 849、1101。

Picture4png

group@i(~!=~[-1]+1)。再对每个差集进行条件分组,将连续的序列分到同一小组,比如 849、1101 分别分到了第 2 和第 3 组。函数 group 用于分组,默认按等值分组,@i 表示按条件分组,~[-1] 表示上一个成员。

Picture5png

A5=A4.news(diff; ITEM_ID, ~1:START_NUM, ~.m(-1):END_NUM)。用 A4 的每条记录的 diff 字段里的每个序列,生成一条新记录,其中,新区间的起止序号取自每个序列的头尾。函数 news 可将集合的每个成员扩展成一条记录。~.m(-1) 表示 ~ 里的倒数第 1 个成员,~.m(1) 表示正数第 1 个成员,简写做 ~1。

Picture6png