Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Postgresql 包含/排除项的父/子表_Postgresql_Recursion_Recursive Query - Fatal编程技术网

Postgresql 包含/排除项的父/子表

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

我有一张有亲子关系的桌子。这种关系可以深入到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;

  • 非递归部分根据
    组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    |
    
  • 现在你有了不需要的名字。现在,您希望找到必须排除的项。将bbb元素作为
    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}     |