【问题标题】:SQL Recursive CTE - Keep reference to a parentSQL Recursive CTE - 保持对父级的引用
【发布时间】:2015-01-10 02:38:31
【问题描述】:

我有一个结构如下的表

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

有什么方法可以实现吗?

谢谢

【问题讨论】:

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


    【解决方案1】:

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

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

    【讨论】:

    • 非常感谢,这正是我想要的。
    【解决方案2】:

    你可以在 cte 表和 usershare 表上做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 
    

    【讨论】:

      【解决方案3】:

      一种方法是在UserCTE 表和share 表之间的连接中使用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 表的userId 列上进行两个左连接,一个到share 表,另一个到UserCTE 表的managerId 列到share 表。然后,您可以在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;
      

      希望这会有所帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-07-27
        • 1970-01-01
        相关资源
        最近更新 更多