【问题标题】:Recursive CTE (T-SQL) Returns Un-expected Result递归 CTE (T-SQL) 返回意外结果
【发布时间】:2017-08-31 12:26:35
【问题描述】:

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

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

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

使用临时数据库; 声明@emp--loyee 桌子 ( EmployeeID int 非空 ,EmployeeName nvarchar(50) NOT NULL 主键(员工 ID) ) 插入@emp 选择 1,“弗雷德” 联盟 选择 2,“玛丽” 联盟 选择 3,“乔” 联盟 选择 4,'比尔' 声明 @grp 表 ( GroupID int 非空 ,组名 nvarchar(50) 主键(组 ID) ) 插入@grp 选择 1,'组 1' 联盟 选择 2,'组 2' 联盟 选择 3,'组 3' 声明@empgrp 表( EmployeeID int 非空 ,GroupID int NOT NULL 主键(员工 ID、组 ID) ) 插入@empgrp 选择 1,1 联盟 选择 2,1 联盟 选择 3,1 联盟 选择 4,2 声明@grpgrp 表( GroupID int 非空 ,ParentGroupID int ,唯一的集群(GroupID,ParentGroupID) ) 插入@grpgrp 选择 1,2 联盟 选择 2,3; WITH AllEmpGroups (EmployeeID,GroupID,RootGroupID) 作为 ( SELECT CAST(NULL as int) as EmployeeID,pgrp.GroupID,pgrp.ParentGroupID 从@grpgrp pgrp 左加入@grpgrp ggrp ON pgrp.ParentGroupID = ggrp.GroupID 联合所有 SELECT e.EmployeeID,eg.GroupID,aeg.RootGroupID 从@emp e 加入@empgrp 例如 ON e.EmployeeID = eg.EmployeeID 加入@grpgrp ggrp ON eg.GroupID = ggrp.GroupID 加入 AllEmpGroups aeg ON aeg.GroupID = ggrp.ParentGroupID ) 选择员工 ID、组 ID、根组 ID 来自 AllEmpGroups

我得到的是:

+------------+---------+-------------+ |员工ID |组ID |根组ID | +------------+---------+-------------+ |空 | 1 | 2 | |空 | 2 | 3 | | 1 | 1 | 3 | | 2 | 1 | 3 | | 3 | 1 | 3 | +------------+---------+-------------+

我期望/想要得到的是:

+------------+---------+-------------+ |员工ID |组ID |根组ID | +------------+---------+-------------+ |空 | 1 | 2 | |空 | 2 | 3 | | 4 | 2 | 3 | | 1 | 1 | 3 | | 2 | 1 | 3 | | 3 | 1 | 3 | +------------+---------+-------------+

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

我错过了什么?

【问题讨论】:

标签: sql sql-server tsql recursion recursive-query


【解决方案1】:

第一:

  1. 您需要为@grpgrp 中的根节点设置一行,其值为3, null
  2. 递归 cte 的锚点(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 |
+------------+---------+---------------+-------------+

【讨论】:

  • 非常感谢。感谢先做层次结构然后加入员工的额外建议!
  • @klzbrt 乐于助人!
【解决方案2】:

开始
WITH AllGroups (RootGroupID,GroupID,ParentGroupID, level)
AS
(
    SELECT GroupID RootGroupID, GroupID, Cast(NULL as int) ParentGroupID, 0 level
    FROM @grp g
    WHERE NOT EXISTS (SELECT 1 FROM @grpgrp gg WHERE gg.GroupID = g.GroupID)

    UNION ALL
    SELECT ag.RootGroupID, gg.GroupID, gg.ParentGroupID, level+1
    FROM @grpgrp gg
    JOIN AllGroups ag
    ON ag.GroupID = gg.ParentGroupID
)


SELECT EmployeeID, ag.GroupID, ParentGroupID, RootGroupID
FROM AllGroups ag
LEFT JOIN  @empgrp eg ON eg.GroupID = ag.GroupID
ORDER BY RootGroupID, level, ParentGroupID, GroupID;

不确定为什么需要该行:

| NULL       |       2 |           3 |

【讨论】:

  • 简单直接。谢谢。
猜你喜欢
  • 2016-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多