【问题标题】:Oracle - SQL with recursive WHERE clauseOracle - 带有递归 WHERE 子句的 SQL
【发布时间】:2011-10-20 16:41:54
【问题描述】:

我有一张表,用于存储我们组织中工作组的层次结构。它看起来像:

CREATE TABLE WORKGROUPS  ( 
    WORKGROUPID         NUMBER NULL,
    NAME                VARCHAR2(100) NOT NULL,
    PARENTWORKGROUPID   NUMBER NOT NULL,
    WORKGROUPLEVEL      CHAR(1) DEFAULT 1 NOT NULL,
    CONSTRAINT WORKGROUPS_PK PRIMARY KEY(WORKGROUPID)
)

例如,工作组的深度可能有三层:

ID 1 - Sales (PARENTWORKGROUPID = 0)
ID 2 - Business Sales (PARENTWORKGROUPID = 1)
ID 3 - West Coast B2B (PARENTWORKGROUPID = 2)

所以 3 的父级是 2,2 的父级是 1,而 1 是没有父级的顶级工作组,所以我们使用 0。

现在我们有一个任务表。每个 TASKS 行都有一个 WORKGROUPID 列,该列指向 WORKGROUPS 表中的一个 WORKGROUPID。

我需要编写一个查询来返回给定顶级工作组下的所有任务,例如销售下的所有内容(在上面的示例中,可能是 WORKGROUPIDs 1、2 或 3。基本上,它是一个递归查询。

我可以想出一些方法来使用 LEFT JOIN 来检查每个级别,但我宁愿远离硬编码级别数的解决方案,因为数据库旨在允许任意数量的层。我能想到的任何其他解决方案都涉及更改表模式,我目前无法这样做。有任何想法吗?谢谢!

【问题讨论】:

    标签: sql database oracle oracle11g


    【解决方案1】:

    Starting with Oracle 11gR2,支持 ANSI 递归 WITH 语法,是 START WITH/CONNECT BY 的替代方案:

    WITH wgs ( workgroupid, name ) AS
    (
        SELECT workgroupid, name FROM workgroups WHERE workgroupid = :top-lev-dept
         UNION ALL
        SELECT w.workgroupid, w.name FROM workgroups w, wgs WHERE parentworkgroupid = wgs.workgroupid
    )
    SELECT ...
    

    这里的关键是:

    WITH view (column_definition) AS
    (
        SELECT root rows
         UNION ALL
        SELECT sub rows FROM table JOIN view ON recursion condition
    )
    

    【讨论】:

    • 谢谢 - 我决定使用带有 CTE 的 START WITH/CONNECT BY 方法,主要是为了学习新的东西,而且它需要对我从中获取这些数据的视图进行最小的更改。
    【解决方案2】:

    Oracle 似乎有自己的递归版本(我使用 SQL Server 和 DB2,它们使用通用表表达式来支持递归),但我认为这可能会得到你想要的:

    WITH WGS (
        WORKGROUPID,
        NAME
    ) AS (
        SELECT WORKGROUPID,
            NAME
        FROM WORKGROUPS
        START WITH WORKGROUPID = :top-lev-dept
        CONNECT BY WORKGROUPID = PRIOR PARENTWORKGROUPID
    )
    
    SELECT DISTINCT T.*
    FROM TASKS
    INNER JOIN WGS W
        ON (T.WORKGROUPID = W.WORKGROUPID)
    

    您显然会将:top-lev-dept 更改为您要搜索的部门。

    如果不是这样,您可以查看the Oracle reference page on Hierarchical Queries。这可能会让你朝着正确的方向开始......

    【讨论】:

    • 太棒了,是的,看起来这个“连接方式”是关键。我会对该主题进行更多研究并从那里开始 - 感谢您的指点!
    • 这基本上就是我所做的。我尝试使用 CONNECT_BY_ROOT 但它似乎不适用于我加入内容的方式。所以我改用 CTE,并更新了我的视图以返回所有行的“根”工作组。现在,我可以从该视图中选择并查询特定的根工作组,简单易行。
    【解决方案3】:

    您需要研究START WITH/CONNECT BY 语法。

    类似:

    select * from workgroups
    start with parentworkgroupid = 0
    connect by prior workgroupid = parentworkgroupid;
    

    完全未经测试,但我认为它会让你开始。

    希望对您有所帮助。

    【讨论】:

    • 非常好,我认为这至少让我朝着正确的方向前进。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-29
    • 1970-01-01
    • 2023-03-31
    • 2012-07-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多