从 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