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 之前,请确保您理解。
请注意,PostgreSQL(至少 9.4 或更早版本)不能(不幸地)将 quals 下推到 CTE 术语中,即使对于非递归 CTE 也是如此。如果将WHERE baseuserid = 101 添加到查询中,查询仍会生成整个 展平表,然后将其大部分丢弃。如果您只想对 一个 baseuserid 执行此递归操作,则必须在递归 CTE 术语的静态联合部分的 WHERE reporttouserid IS NULL 之后添加适当的 WHERE 子句术语。