【问题标题】:SQL Server Recursive CTE - Why this behavior?SQL Server 递归 CTE - 为什么会出现这种行为?
【发布时间】:2016-07-08 20:34:55
【问题描述】:

鉴于这些表格...

CREATE TABLE tblEmployees (
    EmployeeID  SMALLINT,
    ReportsTo   SMALLINT,
    IsBigBoss   BIT);

CREATE TABLE tblTargetEmployees (
    EmployeeID SMALLINT);

INSERT INTO tblEmployees VALUES
(1,NULL,NULL),
(2,1,1),
(3,1,1),
(4,1,1),
(5,1,1),
(6,2,0),
(7,6,0),
(8,6,0),
(9,3,0),
(10,4,0),
(11,10,0),
(12,10,0),
(13,5,0),
(14,2,0),
(15,10,0);

INSERT INTO tblTargetEmployees VALUES
(8),
(9),
(10),
(11),
(12),
(14);

这个查询...

WITH cte AS (
    SELECT e.EmployeeID, BigBossID=e.EmployeeID, e.ReportsTo
        FROM tblEmployees e
        WHERE e.IsBigBoss=1

    UNION all

    SELECT e.EmployeeID, cte.BigBossID, e.ReportsTo
        FROM tblEmployees e
            JOIN cte ON e.ReportsTo=cte.EmployeeID
)

SELECT *
    FROM cte
    WHERE EXISTS (SELECT * FROM tblTargetEmployees te WHERE te.EmployeeID=cte.EmployeeID)
    ORDER by EmployeeID

我得到了预期的结果。我的目标表中的所有六名员工都已返回。但是,如果我将过滤器移到 cte 中,我会删除一个员工 (#8)。

WITH cte AS (
    SELECT e.EmployeeID, BigBossID=e.EmployeeID, e.ReportsTo
        FROM tblEmployees e
        WHERE e.IsBigBoss=1

    UNION all

    SELECT e.EmployeeID, cte.BigBossID, e.ReportsTo
        FROM tblEmployees e
            JOIN cte ON e.ReportsTo=cte.EmployeeID
        WHERE EXISTS (SELECT * FROM tblTargetEmployees te WHERE te.EmployeeID=e.EmployeeID)
)

SELECT *
    FROM cte
    ORDER by EmployeeID

现在,我明白了为什么当我将过滤器移到 cte 时会出现额外的“Big Boss”行,但我很难理解为什么员工 ID 8 会被过滤掉。

非常感谢任何帮助我解决这种行为的简单想法。

【问题讨论】:

  • 也许#8 是被过滤员工的孩子?
  • 天啊!就是这样。谢谢!!

标签: sql sql-server common-table-expression recursive-query


【解决方案1】:

因为 tblTargetEmployees 中不存在 EmployeeId 6,所以当它进行递归并开始添加员工 id 6 时,它会查找 tblTargetEmployees 表中是否存在。如果并且永远不会到达员工 ID 8,则递归行不会停止。

所以要使用数据

  • 2 是 bigboss,在锚表中表示
  • 6 是直接boss,但不存在,因此之后不再调用递归。
  • 8 正在等待被发现.....

将你的 WHERE 语句移到 cte 之外,你会看到你想要的结果

;WITH cte AS (
    SELECT e.EmployeeID, BigBossID=e.EmployeeID, e.ReportsTo
        FROM tblEmployees e
        WHERE e.IsBigBoss=1

    UNION all

    SELECT e.EmployeeID, cte.BigBossID, e.ReportsTo
        FROM tblEmployees e
            JOIN cte ON e.ReportsTo=cte.EmployeeID
)

SELECT *
    FROM cte e
    WHERE EXISTS (SELECT * FROM tblTargetEmployees te WHERE te.EmployeeID=e.EmployeeID)
    ORDER by EmployeeID

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多