SQL递归CTE - 保持对父级的引用

时间:2015-01-09 18:14:16

标签: sql-server tsql sql-server-2012

我有一个包含以下结构的表

userId      userName         managerId
----------- ---------------- -----------
1           John             NULL
2           Charles          1
3           Nicolas          NULL
4           Neil             3

我还有另一张表格,其中包含以下内容

userId      shareId         
----------- -----------
1           1001             
3           1002               

所以我执行以下查询来获取递归CTE:

WITH UserCTE AS (
  SELECT userId, userName, managerId,0 AS steps
  FROM dbo.Users
  WHERE userId = 7

  UNION ALL

  SELECT mgr.userId, mgr.userName, mgr.managerId, usr.steps +1 AS steps
  FROM UserCTE AS usr
    INNER JOIN dbo.Users AS mgr
      ON usr.managerId = mgr.userId
)
SELECT * FROM UserCTE AS u;         

产生以下结果

userId      userName         managerId   steps       
----------- ---------------- ----------- ----------- 
1           John             NULL        0           
2           Charles          1           1           
3           Nicolas          NULL        0           
4           Neil             3           1      

好的,我想知道的是拥有它的用户的shareId,以及属于它们的用户。

预期结果

userId      userName         managerId   steps       shareId
----------- ---------------- ----------- ----------- ----------
1           John             NULL        0           1001
2           Charles          1           1           1001
3           Nicolas          NULL        0           1002
4           Neil             3           1           1002

有没有办法实现它?

由于

3 个答案:

答案 0 :(得分:3)

Share table的锚点查询中加入Users Recursive CTE表。试试这个。

;WITH UserCTE
     AS (SELECT c.userId,
                userName,
                managerId,
                0 AS steps,
                shareId
         FROM   dbo.Users c
                LEFT JOIN share_table s
                  ON c.userId = s.userId
         WHERE  managerId IS NULL
         UNION ALL
         SELECT mgr.userId,
                mgr.userName,
                mgr.managerId,
                usr.steps + 1 AS steps,
                usr.shareId
         FROM   UserCTE AS usr
                INNER JOIN dbo.Users AS mgr
                        ON usr.userId = mgr.managerId)
SELECT *
FROM   UserCTE AS u
ORDER  BY userId; 

答案 1 :(得分:1)

你可以在cte table和usershare table上做left join

WITH UserCTE AS (
  SELECT userId, userName, managerId,0 AS steps
  FROM dbo.Users
  where   managerId IS NULL

  UNION ALL

  SELECT mgr.userId, mgr.userName, mgr.managerId, usr.steps +1 AS steps
  FROM UserCTE AS usr
  INNER JOIN dbo.Users AS mgr
  ON usr.userId = mgr.managerId
  )
SELECT * FROM UserCTE AS u
left join userShare us
on u.managerId = us.userId
or u.userId = us.userId
order by u.userId 

答案 2 :(得分:1)

一种方法是在OR表和UserCTE表之间的连接中使用share。例如:

WITH UserCTE AS (
  SELECT userId, userName, managerId,0 AS steps
  FROM dbo.Users
  WHERE userId = 7

  UNION ALL

  SELECT mgr.userId, mgr.userName, mgr.managerId, usr.steps +1 AS steps
  FROM UserCTE AS usr
    INNER JOIN dbo.Users AS mgr
      ON usr.managerId = mgr.userId
)
SELECT * FROM UserCTE AS u
INNER JOIN [share table] AS s
    ON u.userId = s.userId OR u.managerId s.userId;

但是,如果存在多个级别的管理层次结构,则可能会重复过程。即经理也有经理。另一种方法是将userId表的UserCTE列中的两个左联接一个添加到share表,将另一个联接到managerId UserCTE列的share列表到CASE表。然后,您可以使用shareId列上的WITH UserCTE AS ( SELECT userId, userName, managerId,0 AS steps FROM dbo.Users WHERE userId = 7 UNION ALL SELECT mgr.userId, mgr.userName, mgr.managerId, usr.steps +1 AS steps FROM UserCTE AS usr INNER JOIN dbo.Users AS mgr ON usr.managerId = mgr.userId ) SELECT u.* ,CASE WHEN su.shareId is not null THEN su.shareId WHEN sm.shareId is not null THEN sm.shareId ELSE null END as shareID FROM UserCTE AS u LEFT JOIN [share table] AS su ON u.userId = s.userId LEFT JOIN [share table] AS sm ON u.managerId = s.userId; 语句来决定您需要哪一项。见下文:

{{1}}

希望这有帮助。