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

SQL Recursive CTE - Keep reference to a parent

我有一个 table 具有以下结构

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

我还有另一个 table,其中包含以下内容

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

有什么办法可以实现吗?

谢谢

Recursive CTE 的锚查询中加入 Share tableUsers table。试试这个。

;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; 

你可以在 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 

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

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;

但是,如果存在不止一级的管理层次结构,这可能会导致程序重复。 IE。经理也有经理。另一种方法是在 UserCTE table 的 userId 列上创建两个左连接,一个连接到 share table,另一个连接到 managerId UserCTE table 到 share table 的列。然后,您可以在 shareId 列上使用 CASE 语句来决定您需要哪一个。见下文:

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;

希望对您有所帮助。