postgresql - 如何创建将父 ID 和祖 parent ID 插入数组的递归 CTE 查询

标签 postgresql common-table-expression recursive-query

我有一个正在尝试创建的 postgresql 表。这是我的 cte,我在这里插入值

BEGIN;
CREATE TABLE section (
  id SERIAL PRIMARY KEY,
  parent_id INTEGER REFERENCES section(id) DEFERRABLE,
  name TEXT NOT NULL UNIQUE );
SET CONSTRAINTS ALL DEFERRED;
INSERT INTO section VALUES (1, NULL, 'animal');
INSERT INTO section VALUES (2, NULL, 'mineral');
INSERT INTO section VALUES (3, NULL, 'vegetable');
INSERT INTO section VALUES (4, 1, 'dog');
INSERT INTO section VALUES (5, 1, 'cat');
INSERT INTO section VALUES (6, 4, 'doberman');
INSERT INTO section VALUES (7, 4, 'dachshund');
INSERT INTO section VALUES (8, 3, 'carrot');
INSERT INTO section VALUES (9, 3, 'lettuce');
INSERT INTO section VALUES (10, 11, 'paradox1');
INSERT INTO section VALUES (11, 10, 'paradox2');
SELECT setval('section_id_seq', (select max(id) from section));

WITH RECURSIVE last_run(parent_id, id_list, name_list) AS (
  ???
SELECT id_list, name_list
FROM last_run ???
WHERE ORDER BY id_list;
ROLLBACK;

我知道递归查询是最好的方法,但不确定具体如何实现。到底是什么??? 我想要得到的是下表:

id_list |       name_list        
---------+------------------------
 {1}     | animal
 {2}     | mineral
 {3}     | vegetable
 {4,1}   | dog, animal
 {5,1}   | cat, animal
 {6,4,1} | doberman, dog, animal
 {7,4,1} | dachshund, dog, animal
 {8,3}   | carrot, vegetable
 {9,3}   | lettuce, vegetable
 {10,11} | paradox1, paradox2
 {11,10} | paradox2, paradox1

最佳答案

您可以在单个查询中使用多个递归 CTE:一个用于有效树,另一个用于悖论:

with recursive
  cte as (
    select *, array[id] as ids, array[name] as names
    from section
    where parent_id is null
    union all
    select s.*, s.id||c.ids, s.name||c.names
    from section as s join cte as c on (s.parent_id = c.id)),
  paradoxes as (
    select *, array[id] as ids, array[name] as names
    from section
    where id not in (select id from cte)
    union all
    select s.*, s.id||p.ids, s.name||p.names
    from section as s join paradoxes as p on (s.parent_id = p.id)
    where s.id <> all(p.ids) -- To break loops
  ) 
select * from cte
union all
select * from paradoxes;

结果:

┌────┬───────────┬───────────┬─────────┬────────────────────────┐
│ id │ parent_id │   name    │   ids   │         names          │
├────┼───────────┼───────────┼─────────┼────────────────────────┤
│  1 │      ░░░░ │ animal    │ {1}     │ {animal}               │
│  2 │      ░░░░ │ mineral   │ {2}     │ {mineral}              │
│  3 │      ░░░░ │ vegetable │ {3}     │ {vegetable}            │
│  4 │         1 │ dog       │ {4,1}   │ {dog,animal}           │
│  5 │         1 │ cat       │ {5,1}   │ {cat,animal}           │
│  8 │         3 │ carrot    │ {8,3}   │ {carrot,vegetable}     │
│  9 │         3 │ lettuce   │ {9,3}   │ {lettuce,vegetable}    │
│  6 │         4 │ doberman  │ {6,4,1} │ {doberman,dog,animal}  │
│  7 │         4 │ dachshund │ {7,4,1} │ {dachshund,dog,animal} │
│ 10 │        11 │ paradox1  │ {10}    │ {paradox1}             │
│ 11 │        10 │ paradox2  │ {11}    │ {paradox2}             │
│ 11 │        10 │ paradox2  │ {11,10} │ {paradox2,paradox1}    │
│ 10 │        11 │ paradox1  │ {10,11} │ {paradox1,paradox2}    │
└────┴───────────┴───────────┴─────────┴────────────────────────┘

Demo

如您所见,结果包含两个不需要的行:{10}, {paradox1}{11}, {paradox2}。如何过滤掉它们取决于您。

如果您像 INSERT INTO section VALUES (12, 10, 'paradox3'); 那样追加另一行,则不清楚期望的结果是什么。

关于postgresql - 如何创建将父 ID 和祖 parent ID 插入数组的递归 CTE 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51412078/

相关文章:

java - Spring 数据(其余): Date serialization mapping returns a wrong value

node.js - 如何使用 Node.js 中的钩子(Hook)更改特定列数据? ( Sequelize ,Postgresql)

postgresql - 我可以将数组参数传递到 CTE 中吗?

oracle - Oracle中的父子关系

postgresql - postgres中的递归函数

sql - 每行到列的值

postgresql - 在带有 Microsoft Access 前端的 Postgres 中使用时间数据类型

sql - 使用 SQL Server CTE 返回所有父记录

sql-server - 在函数中使用 CTE 在 SQL Server 上的工作日

sql - 递归选择行