从 SQL 到 SPL:从关系表里找出超集
mysql 库有 2 个表:袋子表、袋子物品关系表,有些袋子是其他袋子的超集。
bag
id |
name |
A |
Bag A |
B |
Bag B |
C |
Bag C |
D |
Bag D |
bag_item
id |
bag_id |
item_id |
1 |
A |
1 |
2 |
A |
2 |
3 |
B |
1 |
4 |
B |
2 |
5 |
B |
3 |
6 |
B |
4 |
7 |
C |
1 |
8 |
C |
4 |
9 |
D |
1 |
10 |
D |
2 |
11 |
D |
3 |
现在要找出每个袋子的超集:
base_bag_id |
superset_bag_id |
A |
B |
A |
D |
C |
B |
D |
B |
SQL:
SELECT
base.id AS base_bag_id,
s.id AS superset_bag_id
FROM bag base
JOIN bag s
ON s.id <> base.id
AND NOT EXiSTS (SELECT 1
FROM bag_item bi
WHERE bi.bag_id = base.id
AND NOT EXISTS (SELECT 1
FROM bag_item si
WHERE si.item_id = bi.item_id
AND si.bag_id = s.id
)
);
这里需要两层循环遍历,SQL 要用三层嵌套配合 JOIN 和难懂的 EXISTS 实现集合运算,理解难度大。SPL 可以简单用二层循环配合直观的集合运算实现。https://try.esproc.com/splx?471
A |
|
1 |
$select * from bag_item.txt |
2 |
=A1.group(bag_id; ~.(item_id):items) |
3 |
=A2.news((b=bag_id, i=items, A2.select( b!=bag_id && i \ items==[])); b:base_bag_id, bag_id:superset_bag) |
A2:按袋子分组,但不汇总,每组是一个袋子以及袋子里物品的集合 items。
A3:两层循环计算出目标结果,\ 表示差集运算。
问题来源:https://stackoverflow.com/questions/78222276/find-supersets-of-association-database-table
英文版 https://c.esproc.com/article/1740043714746