用于展平树的简单公用表表达式

时间:2013-11-11 11:35:42

标签: sql postgresql common-table-expression

以下是我的表格格式。 表名:: USERS

userid reporttouserid
------ ------------
101    NULL
102    101
103    102

现在我需要一个查询来列出101下的所有子用户ID,即102和103两者(103间接在101以下,因为其父102在101以下)

我在postgresql中看到了常见的表表达式,但却无法弄清楚如何去做。

1 个答案:

答案 0 :(得分:5)

PostgreSQL documentation涵盖了此主题。请参阅该页面上给出的递归CTE示例。

递归CTE可能有点难以掌握,但一旦使用它们就非常强大。阅读文档并进行一些实验;你会明白的。

(请务必在您的问题中以表格形式提及您的PostgreSQL版本和显示所需的输出。)

给出演示数据:

create table users (
  userid integer primary key,
  reporttouserid integer references users(userid)
);

insert into users(userid, reporttouserid) values (101,null), (102,101), (103,102);

(如果可能,请在问题中提供此信息,必须创建它才会感到痛苦)

您可以使用以下内容递归地遍历图表:

WITH RECURSIVE flatusers(userid, reporttouserid, baseuserid) AS (
    SELECT userid, reporttouserid, userid AS baseuserid 
    FROM users WHERE reporttouserid IS NULL
    UNION ALL
    SELECT u.userid, u.reporttouserid, f.baseuserid
    FROM flatusers f
    INNER JOIN users u ON f.userid = u.reporttouserid

)
SELECT * FROM flatusers;

产生如下输出:

 userid | reporttouserid | baseuserid 
--------+----------------+------------
    101 |                |        101
    102 |            101 |        101
    103 |            102 |        101
(3 rows)

我相信你可以从那里找出去哪里。在使用之前,请确保理解递归CTE。

请注意,即使对于非递归CTE,PostgreSQL(至少9.4或更早版本)也不能(不幸地)将quals推向CTE术语。如果您在查询中添加WHERE baseuserid = 101,则查询仍会生成整个展平表,然后将大部分表格丢弃。如果要对一个 baseuserid执行此递归操作,则必须在递归CTE术语的静态联合部分中在WHERE之后添加适当的WHERE reporttouserid IS NULL子句。< / p>