【问题标题】:CTE Recursion Ordered TreeCTE 递归有序树
【发布时间】:2017-11-28 13:00:14
【问题描述】:

我用以下数据创建了这个SQL Fiddle

userId    userName    managerId
======    ========    =========
1         Adam        NULL
2         Brett       1
3         Chris       2
4         George      1
5         David       3
6         Elliot      5
7         Fred       5
8         Harry       4

如何返回一棵树,以便按以下顺序返回数据:

Adam
  Brett
    Chris
      David
        Elliot
        Fred
  George
    Harry

我不担心缩进,当然我不能只按名称排序(以防 Fred 被更正为 Alfred)。

这是我目前所得到的:

WITH UserCTE AS (
  SELECT userId, userName, managerId, 0 AS EmpLevel
  FROM Users where managerId is null

  UNION ALL

  SELECT usr.userId, usr.userName, usr.managerId, mgr.[EmpLevel]+1
  FROM Users AS usr
    INNER JOIN UserCTE AS mgr
      ON usr.managerId = mgr.userId where usr.managerId IS NOT NULL
)
SELECT * 
  FROM UserCTE AS u 
  ORDER BY EmpLevel;

【问题讨论】:

    标签: sql sql-server common-table-expression recursive-cte


    【解决方案1】:

    您需要获取每个人的完整路径,然后按此排序:

    WITH UserCTE AS (
          SELECT userId, userName, managerId, 0 AS EmpLevel,
                 CONVERT(VARCHAR(MAX), '/' + userName) as path
          FROM Users 
          WHERE managerId is null
          UNION ALL
          SELECT usr.userId, usr.userName, usr.managerId, mgr.[EmpLevel]+1,
                 CONVERT(VARCHAR(MAX), mgr.path + '/' + usr.userName)
          FROM Users usr INNER JOIN
               UserCTE mgr
               ON usr.managerId = mgr.userId 
          WHERE usr.managerId IS NOT NULL  -- this is unnecessary
         )
    SELECT * 
    FROM UserCTE AS u 
    ORDER BY path;
    

    【讨论】:

    • 查询似乎创建了一个“亚当//布雷特”。我认为查询的第一部分需要 CONVERT(VARCHAR(MAX), userName) 作为路径。
    • @openshac 。 . .我认为这不会影响排序,但我将 / 移到了我真正想要的位置。
    【解决方案2】:

    如何使用 sql server hierarchyid 以正确的顺序对这些进行排序: SQL Fiddle

    MS SQL Server 2014 架构设置

    CREATE TABLE [dbo].[Users](
        [userId] [int] ,
        [userName] [varchar](50) ,
        [managerId] [int] ,
       )
    
    INSERT INTO dbo.Users
        ([userId], [userName], [managerId])
    VALUES
    (1,'Adam',NULL),
    (2,'Brett',1),
    (3,'Chris',2),
    (4,'George',1),
    (5,'David',3),
    (6,'Elliot',5),
    (7,'Frank',5),
    (8,'Harry',4)
    

    查询 1

    WITH UserCTE AS (
      SELECT userId, userName, managerId, hierarchyid::GetRoot() AS EmpLevel
      FROM Users where managerId is null
    
      UNION ALL
    
      SELECT usr.userId, usr.userName, usr.managerId
             , cast(mgr.EmpLevel.ToString() + cast(usr.userId As varchar(30)) + '/' as hierarchyid) as EmpLevel
      FROM Users AS usr
        INNER JOIN UserCTE AS mgr
          ON usr.managerId = mgr.userId where usr.managerId IS NOT NULL
    )
    SELECT * , EmpLevel.ToString()
      FROM UserCTE AS u 
      ORDER BY EmpLevel
    

    Results

    | userId | userName | managerId | EmpLevel |           |
    |--------|----------|-----------|----------|-----------|
    |      1 |     Adam |    (null) |          |         / |
    |      2 |    Brett |         1 |     aA== |       /2/ |
    |      3 |    Chris |         2 |     a8A= |     /2/3/ |
    |      5 |    David |         3 |     a+M= |   /2/3/5/ |
    |      6 |   Elliot |         5 |     a+OU | /2/3/5/6/ |
    |      7 |    Frank |         5 |     a+Oc | /2/3/5/7/ |
    |      4 |   George |         1 |     hA== |       /4/ |
    |      8 |    Harry |         4 |     hog= |     /4/8/ |
    

    【讨论】:

    • 太好了,EmpLevel 字段对我来说真的很有用。
    猜你喜欢
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 2012-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-28
    相关资源
    最近更新 更多