sql - 递归 CTE (T-SQL) 返回意外结果

标签 sql sql-server t-sql recursion recursive-query

我盯着这段代码太久了,试图找出为什么我的最终查询返回意外的结果。

任何帮助将不胜感激。提前致谢。

给出以下代码(在 SQL Server 2008 R2 上运行):

USE tempdb;

DECLARE @emp--loyee
TABLE (
    EmployeeID int NOT NULL
    ,EmployeeName nvarchar(50) NOT NULL
    PRIMARY KEY(EmployeeID)
)

INSERT INTO @emp
SELECT 1,'Fred'
UNION
SELECT 2,'Mary'
UNION
SELECT 3,'Joe'
UNION
SELECT 4,'Bill'

DECLARE @grp TABLE (
    GroupID int NOT NULL
    ,GroupName nvarchar(50)
    PRIMARY KEY(GroupID)
)

INSERT INTO @grp
SELECT 1,'Group 1'
UNION
SELECT 2,'Group 2'
UNION
SELECT 3,'Group 3'


DECLARE @empgrp TABLE (
    EmployeeID int NOT NULL
    ,GroupID int NOT NULL
    PRIMARY KEY (EmployeeID,GroupID)
)

INSERT INTO @empgrp
SELECT 1,1
UNION
SELECT 2,1
UNION
SELECT 3,1
UNION
SELECT 4,2

DECLARE @grpgrp TABLE (
    GroupID int NOT NULL
    ,ParentGroupID int
    ,UNIQUE CLUSTERED(GroupID,ParentGroupID)
)

INSERT INTO @grpgrp
SELECT 1,2
UNION
SELECT 2,3;


WITH AllEmpGroups (EmployeeID,GroupID,RootGroupID)
AS
(
    SELECT CAST(NULL as int) as EmployeeID,pgrp.GroupID,pgrp.ParentGroupID
    FROM @grpgrp pgrp LEFT JOIN @grpgrp ggrp
    ON pgrp.ParentGroupID = ggrp.GroupID
    UNION ALL
    SELECT e.EmployeeID,eg.GroupID,aeg.RootGroupID
    FROM @emp e JOIN @empgrp eg
    ON e.EmployeeID = eg.EmployeeID
    JOIN @grpgrp ggrp
    ON eg.GroupID = ggrp.GroupID
    JOIN AllEmpGroups aeg
    ON aeg.GroupID = ggrp.ParentGroupID
)

SELECT EmployeeID,GroupID,RootGroupID
FROM AllEmpGroups

我得到的是:

+------------+---------+-------------+
| EmployeeID | GroupID | RootGroupID |
+------------+---------+-------------+
| NULL       |       1 |           2 |
| NULL       |       2 |           3 |
| 1          |       1 |           3 |
| 2          |       1 |           3 |
| 3          |       1 |           3 |
+------------+---------+-------------+

我期望/想要得到的是:

+------------+---------+-------------+
| EmployeeID | GroupID | RootGroupID |
+------------+---------+-------------+
| NULL       |       1 |           2 |
| NULL       |       2 |           3 |
| 4          |       2 |           3 |
| 1          |       1 |           3 |
| 2          |       1 |           3 |
| 3          |       1 |           3 |
+------------+---------+-------------+

底线,我想要给定根组下所有员工的完整递归堆栈,每行都有根组 ID。

我错过了什么?

最佳答案

第一:

  1. 您需要在 @grpgrp 中为根节点添加一行,其值为 3, null
  2. 递归 cte 的 anchor (union all 之前的部分)需要是祖先首次递归的根节点 (3, null)。
...

INSERT INTO @grpgrp
SELECT 1,2
UNION all
SELECT 2,3
UNION all
select 3, null;

WITH AllEmpGroups (EmployeeID,GroupID,RootGroupID)
AS
(
    SELECT CAST(NULL as int) as EmployeeID,pgrp.GroupID, ParentGroupID = pgrp.GroupID
    FROM @grpgrp pgrp LEFT JOIN @grpgrp ggrp
      ON pgrp.ParentGroupID = ggrp.GroupID
    where pgrp.ParentGroupId is null
    UNION ALL
    SELECT e.EmployeeID,eg.GroupID,aeg.RootGroupID
    FROM @emp e JOIN @empgrp eg
    ON e.EmployeeID = eg.EmployeeID
    JOIN @grpgrp ggrp
    ON eg.GroupID = ggrp.GroupID
    JOIN AllEmpGroups aeg
    ON aeg.GroupID = ggrp.ParentGroupID
)

SELECT EmployeeID,GroupID,RootGroupID
FROM AllEmpGroups

rextester 演示:http://rextester.com/CBWY80387

返回:

+------------+---------+-------------+
| EmployeeID | GroupID | RootGroupID |
+------------+---------+-------------+
| NULL       |       3 |           3 |
| 4          |       2 |           3 |
| 1          |       1 |           3 |
| 2          |       1 |           3 |
| 3          |       1 |           3 |
+------------+---------+-------------+

除此之外,我将首先构建组层次结构,然后加入员工,如下所示:

WITH AllEmpGroups (GroupID,ParentGroupID,RootGroupID)
AS
(
    SELECT pgrp.GroupID, pgrp.ParentGroupID, RootGroupId = GroupID
    FROM @grpgrp pgrp 
    where pgrp.ParentGroupId is null
    UNION ALL
    SELECT ggrp.GroupID,ggrp.ParentGroupID,aeg.RootGroupID
    FROM  @grpgrp ggrp
    inner JOIN AllEmpGroups aeg
        ON aeg.GroupID = ggrp.ParentGroupID

)
SELECT eg.EmployeeID,aeg.*
FROM AllEmpGroups aeg
    left JOIN @empgrp eg 
        ON eg.GroupID = aeg.GroupID

rextester 演示:http://rextester.com/FAK76354

返回:

+------------+---------+---------------+-------------+
| EmployeeID | GroupID | ParentGroupID | RootGroupID |
+------------+---------+---------------+-------------+
| NULL       |       3 | NULL          |           3 |
| 4          |       2 | 3             |           3 |
| 1          |       1 | 2             |           3 |
| 2          |       1 | 2             |           3 |
| 3          |       1 | 2             |           3 |
+------------+---------+---------------+-------------+

关于sql - 递归 CTE (T-SQL) 返回意外结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43238821/

相关文章:

PHP SQL 安全性

php - 如何使用 php/mysql 预加载或类似方法优化 mysql 查询

SQL 更新查询

mysql - 通过多个id查询数据(数量较多)

sql - SQL 中的字符串连接不起作用

sql-server - 更新长度 > 50 的行

mysql - 如何使用sql语句达到我想要的结果?

sql - 表: How to get all violations?中的多个约束

t-sql - 2 个应该相同的 T-SQL 查询却没有

sql-server - 将增量值插入表中