Postgresql 包含/排除项的父/子表
我有一张有亲子关系的桌子。这种关系可以深入到n级。 还有一个包含属于组的元素的表Postgresql 包含/排除项的父/子表,postgresql,recursion,recursive-query,Postgresql,Recursion,Recursive Query,我有一张有亲子关系的桌子。这种关系可以深入到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 ); IN
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;
组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\u id=2
:有一行contains=true
和一行contains=false
。这应该被排除在外。因此,必须对每个parent\u id
的所有名称进行分组。可以使用布尔运算符聚合contains值。如果所有元素均为true
,则聚合函数bool\u和仅给出true
。因此,bbb
将得到一个false
(由于某些原因,递归部分中不允许使用GROUP BY
,因此需要将聚合作为一个集合进行):
| 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 |
父\u id
对未列出的名称进行分组。FILTER
子句仅聚合bool\u和
为true
的元素。当然,您需要在窗口函数中再次执行此操作。这将创建重复记录,可通过DISTINCT
子句删除这些记录1
进行过滤):
| 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 |
| group_id | array_agg |
|----------|-----------|
| 5 | {bbb,ccc} |
| 4 | {aaa,bbb} |
| 6 | {aaa,bbb} |
| 7 | {aaa,ccc} |
| 2 | {aaa} |
| 3 | {bbb} |
| 1 | {aaa} |