从 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