【问题标题】:CTE Recursive QueriesCTE 递归查询
【发布时间】:2014-08-13 13:16:16
【问题描述】:

我有一张员工记录表,其中显示了员工之间的关系以及他们向谁报告:

From_ID   position          TO_ID   position
----------------------------------------
1         Lowest_employee   3       employee
3         employee          4       employee
4         employee          5       BOSS
2         Lowest_employee   6       employee
6         employee          3       employee
10        Lowest_employee   50      BOSS2

我想用员工/老板 ID 显示如下所示的结果:

EmployeeID   BossID
--------------------
1            5
2            5
10           50

这意味着员工 1 和 2 向 ID 5 报告,员工 10 向 ID 50 的另一个老板报告。

我知道我需要使用 CTE 和递归查询,但不明白它是如何完成的,我对 CTE 递归查询比较陌生。

我读了这篇文章,但对我来说没有任何意义MS link

任何有关实现此目的所需查询的帮助都会很有用。

【问题讨论】:

  • 我很难理解你在问什么,重新阅读你的问题(忘记你所知道的),看看你认为这对不知道你的问题的人是否有意义.
  • 其实他的问题很清楚
  • 到目前为止你尝试了什么?
  • @hoangnnm 真的吗?我已经读了几遍了,我只是对发生的事情有所了解。如果您必须多次阅读才能理解,那么就不是那么清楚了..在我看来
  • SQL Server 文档的递归 CTE 部分几乎有这个确切的用例:technet.microsoft.com/en-us/library/ms186243(v=sql.105).aspx

标签: sql sql-server recursion common-table-expression


【解决方案1】:
WITH    q (employee, boss) AS
        (
        SELECT  fromId, toId
        FROM    mytable
        WHERE   fromId NOT IN
                (
                SELECT  toId
                FROM    mytable
                )
        UNION ALL
        SELECT  employee, toId
        FROM    q
        JOIN    mytable t
        ON      t.fromId = boss
        )
SELECT  *
FROM    q
WHERE   boss NOT IN
        (
        SELECT  fromId
        FROM    mytable
        )

【讨论】:

  • 正在准备与您发布的类似的答案,因此您可以根据需要在代码中添加此小提琴:sqlfiddle.com/#!3/98a38/1
【解决方案2】:

这包括设置测试数据,但是我认为这是您想要的:

测试数据:

DECLARE @Table TABLE
(
    From_ID int, 
    TO_ID int
)
INSERT INTO @Table VALUES(1,3)
INSERT INTO @Table VALUES(3,4)
INSERT INTO @Table VALUES(4,5)
INSERT INTO @Table VALUES(2,6)
INSERT INTO @Table VALUES(6,3)
INSERT INTO @Table VALUES(10,50)

查询以获得答案:

;WITH Hierarchy (Employee, Superior, QueryLevel)
AS
(
    --root is all employees that have no subordinates
    SELECT  E.From_ID, E.TO_ID, 1
    FROM    @Table E
    LEFT
    JOIN    @Table S
            ON  S.TO_ID = E.From_ID
    WHERE   S.TO_ID IS NULL
    --recurse up tree to final superior
    UNION ALL
    SELECT  H.Employee, S.TO_ID, H.QueryLevel + 1
    FROM    Hierarchy H
    JOIN    @Table S
            ON  S.From_ID = H.Superior
)
SELECT Employee, Superior 
FROM
(
    SELECT  *, ROW_NUMBER() OVER(PARTITION BY Employee ORDER BY QueryLevel DESC) AS RowNumber 
    FROM Hierarchy
) H
WHERE RowNumber = 1

基本上,这是由:

1) 获取所有没有报告人的员工(根)

2) 遍历boss,记录'level'

3) 使用 over/partition 仅选择“最终”boss

【讨论】:

  • 所以这意味着我必须创建这个表或者它只是为了测试目的?
  • 仅用于测试目的 - 将 @Table 替换为您已有的表格 :)
  • 查询的唯一问题是:) The statement terminated. The maximum recursion 100 has been exhausted before statement completion.
  • @AndreyIvanov:这很可能意味着您的数据中有循环(当然,除非您在一家拥有 100 多个管理层的公司工作)
  • @AndreyIvanov:将OPTION (MAXRECURSION 0) 附加到查询的末尾。请注意,如果您确实有循环(您很可能会这样做),此查询将永远不会自行结束,最终会耗尽服务器资源,严重影响其性能。
【解决方案3】:

你可以试试这样的吗?

DECLARE @Employees TABLE (
    EmployeeId INT,
    PositionName VARCHAR(50),
    ReportsToId INT);
INSERT INTO @Employees VALUES (1, 'Driver', 3);
INSERT INTO @Employees VALUES (3, 'Head of Driving Pool', 4);
INSERT INTO @Employees VALUES (4, 'Corporate Flunky', 5);
INSERT INTO @Employees VALUES (2, 'Window Cleaner', 6);
INSERT INTO @Employees VALUES (6, 'Head of Office Services', 3);
INSERT INTO @Employees VALUES (10, 'Minion', 50);
INSERT INTO @Employees VALUES (5, 'BOSS', NULL);
INSERT INTO @Employees VALUES (50, 'BOSS2', NULL);
WITH Employees AS (
    SELECT
        EmployeeId,
        1 AS [Level],
        EmployeeID AS [Path],
        ISNULL(ReportsToId, EmployeeId) AS ReportsToId
    FROM 
        @Employees
    WHERE 
        ReportsToId IS NULL
    UNION ALL
    SELECT
        e.EmployeeID,
        x.[Level] + 1 AS [Level],
        x.[Path] + e.EmployeeID AS [Path],
        x.ReportsToId
    FROM 
        @Employees e
        INNER JOIN Employees x ON x.EmployeeID = e.ReportsToId)
SELECT
    ec.EmployeeId,
    e.PositionName,
    ec.[Level],
    CASE WHEN ec.ReportsToId = ec.EmployeeId THEN NULL ELSE ec.ReportsToId END AS ReportsToId --Can't really report to yourself
FROM 
    Employees ec
    INNER JOIN @Employees e ON e.EmployeeId = ec.EmployeeId
ORDER BY 
    ec.[Path];

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-25
    • 2016-09-28
    • 2014-03-29
    • 2014-08-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多