Postgres:使用WITH RECURSIVE构建项目列表及其父项

时间:2018-05-08 13:44:09

标签: sql postgresql hierarchical-data recursive-query

我的架构看起来像这样:

CREATE TABLE category (
  id SERIAL PRIMARY KEY,
  parent INTEGER REFERENCES category(id) DEFERRABLE,
  name TEXT NOT NULL UNIQUE );
SET CONSTRAINTS ALL DEFERRED;

我添加的行是:

INSERT INTO category VALUES (1, NULL, 'animal');
INSERT INTO category VALUES (2, 1, 'dog');
INSERT INTO category VALUES (3, 1, 'cat');
INSERT INTO category VALUES (4, 3, 'siamese');
INSERT INTO category VALUES (5, 3, 'persian');
INSERT INTO category VALUES (6, 7, 'scary1');
INSERT INTO category VALUES (7, 6, 'scary2');

我正在尝试弄清楚如何使用WITH RECURSIVE递归地查询它,以获得看起来如此的结果:

   ids   |         names      
---------+------------------------
 {1}     | animal
 {2,1}   | dog, animal
 {3,1}   | cat, animal
 {4,3,1} | siamese, cat, animal
 {5,3,1} | persian, cat, animal
 {6,7}   | scary1, scary2
 {7,6}   | scary2, scary1

其中ids是一个包含每个父项的数组,直到根,其中names是一个字符串,每个名称用逗号分隔。 我还需要处理悖论条件而不会挂起。

有人能指出我正确的方向吗?

1 个答案:

答案 0 :(得分:2)

由于数据中存在循环依赖关系,因此必须检查id数组中是否已存在下一个引用行的ids。在最终查询中使用distinct on (id),然后选择包含最大ids数组的行。

with recursive categories as (
    select id, parent, array[id] as ids, name as names
    from category
union all
    select cs.id, c.parent, ids || c.id, concat(names, ', ', name)
    from categories cs
    join category c on cs.parent = c.id
    where c.id <> all(ids)
)
select distinct on (id) ids, names
from categories
order by id, cardinality(ids) desc;

   ids   |        names         
---------+----------------------
 {1}     | animal
 {2,1}   | dog, animal
 {3,1}   | cat, animal
 {4,3,1} | siamese, cat, animal
 {5,3,1} | persian, cat, animal
 {6,7}   | scary1, scary2
 {7,6}   | scary2, scary1
(7 rows)