2017-04-05 96 views
2

我一直在盯着這段代碼太長,試圖找出爲什麼我的最終查詢返回意外的結果。遞歸CTE(T-SQL)返回非預期結果

任何幫助將不勝感激。提前致謝。

 
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 

我得到的是::

考慮下面的代碼(SQL Server 2008 R2上運行)

 
+------------+---------+-------------+ 
| 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在每一行上。

我錯過了什麼?

+0

如何使用'hierarchyid'數據類型。 – Hackerman

+0

從「SQL Server 2008」開始https://docs.microsoft.com/en-us/sql/t-sql/data-types/hierarchyid-data-type-method-reference – Hackerman

回答

2

第一:

  1. 您需要爲根節點行@grpgrp與遞歸CTE值3, null
  2. 錨(在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 | 
+------------+---------+---------------+-------------+ 
+0

非常感謝。感謝額外的建議,首先完成層次結構,然後加入員工! – klzbrt

+0

@klzbrt樂意幫忙! – SqlZim

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 | 
+0

簡單而直接。謝謝。 – klzbrt