【问题标题】:Does PostgreSQL have a pseudo-column like "LEVEL" in Oracle?PostgreSQL 在 Oracle 中是否有类似“LEVEL”的伪列?
【发布时间】:2023-11-12 23:02:02
【问题描述】:

PostgreSQL 在 Oracle 中是否有类似“LEVEL”的伪列?
如果没有,那我们如何创建一个类似于“LEVEL”的列?

【问题讨论】:

    标签: oracle postgresql connect-by hierarchical-query recursive-cte


    【解决方案1】:

    Postgres 没有hierarchical queries。没有CONNECT BY,因此也没有LEVEL

    附加模块 tablefunc 提供了函数connectby() 做几乎相同的事情。见:

    或者您可以使用标准的 recursive CTElevel 列来做类似的事情,每次递归都会增加。
    Oracle 中的这个查询:

    SELECT employee_id, last_name, manager_id, LEVEL
    FROM   employees
    CONNECT BY PRIOR employee_id = manager_id;
    

    .. 可以在 Postgres 中翻译成这个递归 CTE:

    WITH RECURSIVE cte AS (
       SELECT employee_id, last_name, manager_id, 1 AS level
       FROM   employees
    
       UNION  ALL
       SELECT e.employee_id, e.last_name, e.manager_id, c.level + 1
       FROM   cte c
       JOIN   employees e ON e.manager_id = c.employee_id
       )
    SELECT *
    FROM   cte;
    

    【讨论】:

    • 是的。 CONNECT BY 可以表达的东西更干净、更简单,但比WITH RECURSIVE 灵活得多。
    【解决方案2】:

    是的,Postgres 像 Oracle 一样支持“LEVEL”。

    但是,正如其他答案所指出的,您必须加载 tablefunc 扩展。

    如果您对 Postgres 数据库具有管理员访问权限,则可以使用以下命令加载它:

    CREATE EXTENSION IF NOT EXISTS tablefunc;

    更多信息请查看文档

    https://www.postgresql.org/docs/current/static/tablefunc.html

    这是我们的一款应用中connectby 的真实示例。我们正在使用它来查找通过其报告树向经理报告的所有人员。

    SELECT system_user.system_user_id
        , system_user.first_name
        , system_user.last_name
        , team.mgr_id as managers_system_user_id
        , team.level
        , team.hierarchy
        FROM connectby('system_user_manager_rltnp'
                       , 'system_user_id'
                       , 'system_users_managers_id'
                       , 2963049 -- the users system_user_id
                       , 5       -- the max levels of depth
                       , '~')    -- the hierarchy delimiter
        AS team(rpt_id numeric, mgr_id numeric, level int, hierarchy text),
        system_user
        WHERE team.rpt_id = system_user.system_user_id
    

    它会返回这样的结果。在这里您可以看到级别,以及整个层次结构作为字符串。

    "system_user_id","first_name","last_name","managers_system_user_id","level","hierarchy"
    "2963049","Debbie","Buswell","",0,"2963049"
    "2963045","Linda","Simply","2963049",1,"2963049~2963045"
    "2963047","Cindy","Brouillard","2963049",1,"2963049~2963047"
    "2963048","Sharon","Burns","2963049",1,"2963049~2963048"
    "2963050","Marie-Eve","Casper","2963049",1,"2963049~2963050"
    "2963051","Tammy","Cody","2963049",1,"2963049~2963051"
    

    【讨论】:

      【解决方案3】:

      如果您启用tablefunc 扩展。语法稍有不同,但如果您从 oracle 中理解 connect by,您将在大约 90 秒内掌握它。当我将 oracle 系统转换为 postgres 系统时,它很棒并且节省了我的培根。

      我在一个类似的问题上提供了所有细节。
      * Connect By answer

      【讨论】: