【问题标题】:simple common table expression to flatten a tree用于展平树的简单公用表表达式
【发布时间】:2013-11-11 11:35:42
【问题描述】:

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

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

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

我在 postgresql 中看到了公用表表达式,但不知道如何去做。

【问题讨论】:

  • 请说明您尝试了什么,以及为什么它不适合您。
  • 到目前为止,我所做的是通过加入 userid 来选择直接子代,并将其传递给 java 后端的递归函数以查找后续用户。我宁愿在 sql 本身中执行此操作。我无法理解如何在 sql 中编写这种递归查询。谢谢
  • 如果没有记错的话,PG 文档中的 with recursive 示例的查询与您最终将使用的查询几乎相同。

标签: sql postgresql common-table-expression


【解决方案1】:

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 子句术语。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多