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

nig*_*fly 0 sql postgresql common-table-expression

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

userid reporttouserid
------ ------------
101    NULL
102    101
103    102
Run Code Online (Sandbox Code Playgroud)

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

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

Cra*_*ger 5

PostgreSQL文档涵盖了这个主题.请参阅该页面上给出的递归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);
Run Code Online (Sandbox Code Playgroud)

(如果可能的话,请在问题中提供此信息,必须创建它是一件痛苦的事)

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

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;
Run Code Online (Sandbox Code Playgroud)

产生如下输出:

 userid | reporttouserid | baseuserid 
--------+----------------+------------
    101 |                |        101
    102 |            101 |        101
    103 |            102 |        101
(3 rows)
Run Code Online (Sandbox Code Playgroud)

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

请注意,PostgreSQL(至少9.4或更早版本)不能(不幸的是)将quals推向CTE术语,即使对于非递归CTE也是如此.如果您添加WHERE baseuserid = 101到查询中,查询仍将生成整个展平表,然后将大部分表扔掉.如果只想对一个 baseuserid 执行此递归操作,则必须在递归CTE术语的静态联合部分中添加适当的WHERE子句WHERE reporttouserid IS NULLterm.