PostgreSQL:递归加入第二个 table

PostgreSQL: recursively join a second table

我正在努力解决 PostgreSQL 中的递归问题。我需要加入第一个 table 和第二个 table,然后在第二个 table 中递归加入。我看了很多例子,但大多数都是关于在单个 table 中查找父记录,这让我非常困惑。

这是一个包含 tables thingcategory 的最小示例。 thing 中的记录可能有也可能没有类别:

id name category
1 a5 3
2 passat 2
3 apple NULL

category 中的记录可能在同一个 table 中有一个或多个父项:

id name parent_category
1 vehicle NULL
2 car 1
3 coupe 2

我要查找的结果是所有事物及其类别的组合,以及类别级别(1 为直接父级,2 为以上级别)。

thing_name category_name level
a5 coupe 1
a5 car 2
a5 vehicle 3
passat car 1
passat vehicle 2
apple NULL NULL

我这里有一个数据库 Fiddle:https://www.db-fiddle.com/f/b7V8ddragZZ9x2RsMkdFYn/5

CREATE TABLE category (
  id INT,
  name TEXT,
  parent_category INT
);

INSERT INTO category VALUES (1, 'vehicle', null);
INSERT INTO category VALUES (2, 'car', 1);
INSERT INTO category VALUES (3, 'coupe', 2);

CREATE TABLE thing (
  id INT,
  name TEXT,
  category INT
);

INSERT INTO thing VALUES (1, 'a5', 3);
INSERT INTO thing VALUES (2, 'passat', 2);
INSERT INTO thing VALUES (3, 'apple', null);

使用 CTE 连接表,为您提供组合的树状视图 thing_categories,然后您可以将其与普通递归 CTE 一起使用。


with recursive join_thing_category as (
  select thing.id as thing_id,
  thing.name as thing_name,
  thing.category as thing_category,
  category.id as category_id,
  category.name as category_name,
  category.parent_category as parent_category
  from thing left join category on thing.category=category.id
  ),
recursive_part(n) as (
  select thing_id, thing_name, thing_category, category_id, category_name, parent_category, (0*parent_category) + 1 as level from join_thing_category
  union all
  select 1, thing_name, thing_category, cat.id category_id, cat.name, cat.parent_category as parent, level+1 as level from recursive_part rp cross join category cat
  where cat.id=rp.parent_category
  )
select thing_name, category_name, level from recursive_part order by 1, 2, 3 limit 1024;
thing_name category_name level
a5 car 2
a5 coupe 1
a5 vehicle 3
apple
passat car 1
passat vehicle 2

View on DB Fiddle

(0*parent_category) + 1 as level 位是为了让没有类别的事物的级别为 NULL 而不是 1。