我有一张有亲子关系的桌子。这种关系可以达到n级深层次。 还有一个表格,其中的元素属于一个组。
CREATE TABLE group_children(
id serial PRIMARY KEY,
parent_id integer,
children_id integer,
contains boolean
);
CREATE TABLE group_item(
id serial PRIMARY KEY,
group_id integer,
name text
);
INSERT INTO group_children(parent_id, children_id, contains) VALUES
(1, 2, true),
(1, 3, false),
(2, 4, true),
(2, 5, false),
(3, 6, true),
(3, 7, false);
INSERT INTO group_item(group_id, name) VALUES
(4, 'aaa'),
(4, 'bbb'),
(5, 'bbb'),
(5, 'ccc'),
(6, 'aaa'),
(6, 'bbb'),
(7, 'aaa'),
(7, 'ccc');
因此,我们可以将该数据表示为 不必采用二叉树的形式,只是一个简单的情况。群组可以包含m个孩子。
需要从右到左阅读。组4包含['aaa','bbb'],组5-['bbb','ccc']。第2组包含第4组的所有项目,但不包括第5组。因此,第2组包含['aaa']。等等。毕竟,计算组1将包含['aaa']。
问题是:如何构建sql查询以获取属于组1的所有项目?
我所能做的:
WITH RECURSIVE r AS (
SELECT group_children.parent_id, group_children.children_id, group_children.contains, group_item.name
FROM group_children
LEFT JOIN group_item ON group_children.children_id = group_item.group_id
WHERE parent_id = 1
UNION ALL
SELECT group_children.parent_id, group_children.children_id, group_children.contains, group_item.name
FROM group_children
LEFT JOIN group_item ON group_children.children_id = group_item.group_id
JOIN r ON group_children.parent_id = r.children_id
)
SELECT * FROM r;
答案 0 :(得分:2)
WITH RECURSIVE items AS (
SELECT -- 1
group_id,
array_agg(name)
FROM
group_Item
GROUP BY group_id
UNION
SELECT DISTINCT
parent_id,
array_agg(unnest) FILTER (WHERE bool_and) OVER (PARTITION BY parent_id) -- 5
FROM (
SELECT
parent_id,
unnest,
bool_and(contains) OVER (PARTITION BY parent_id, unnest) -- 4
FROM items i
JOIN group_children gc -- 2
ON i.group_id = gc.children_id,
unnest(array_agg) -- 3
) s
)
SELECT * FROM items
group_id
聚合所有名称结果是:
| group_id | array_agg | id | parent_id | children_id | contains | unnest |
|----------|-----------|----|-----------|-------------|----------|--------|
| 4 | {aaa,bbb} | 3 | 2 | 4 | true | aaa |
| 4 | {aaa,bbb} | 3 | 2 | 4 | true | bbb |
| 5 | {bbb,ccc} | 4 | 2 | 5 | false | bbb |
| 5 | {bbb,ccc} | 4 | 2 | 5 | false | ccc |
| 6 | {aaa,bbb} | 5 | 3 | 6 | true | aaa |
| 6 | {aaa,bbb} | 5 | 3 | 6 | true | bbb |
| 7 | {aaa,ccc} | 6 | 3 | 7 | false | aaa |
| 7 | {aaa,ccc} | 6 | 3 | 7 | false | ccc |
parent_id = 2
的bbb元素为例:一行包含contains = true
,另一行包含contains = false
。这应该排除在外。因此,每个parent_id
的名称都必须分组。包含值可以使用布尔运算符聚合。如果所有元素均为bool_and
,则聚合函数true
仅给出true
。因此bbb
将得到一个false
(由于某些原因不允许在递归部分中使用GROUP BY
,因此聚合需要以window function的形式进行):结果:
| parent_id | unnest | bool_and |
|-----------|--------|----------|
| 2 | aaa | true |
| 2 | bbb | false |
| 2 | bbb | false |
| 2 | ccc | false |
| 3 | aaa | false |
| 3 | aaa | false |
| 3 | bbb | true |
| 3 | ccc | false |
parent_id
对未嵌套的名称进行分组。 FILTER
子句仅聚合bool_and
为true
的元素。当然,您需要再次在窗口函数中执行此操作。这样会创建重复记录,可以通过DISTINCT
子句最终结果(当然可以由元素1
过滤掉):
| group_id | array_agg |
|----------|-----------|
| 5 | {bbb,ccc} |
| 4 | {aaa,bbb} |
| 6 | {aaa,bbb} |
| 7 | {aaa,ccc} |
| 2 | {aaa} |
| 3 | {bbb} |
| 1 | {aaa} |