Sql CTE递归有序树

Sql CTE递归有序树,sql,sql-server,common-table-expression,recursive-cte,Sql,Sql Server,Common Table Expression,Recursive Cte,我已经用以下数据创建了这个 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

我已经用以下数据创建了这个

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
我不担心缩进,当然我不能只按名字订购(以防弗雷德改成阿尔弗雷德)

到目前为止,我得到的是:

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;

您需要通过获取每个人的完整路径,然后根据该路径进行排序:

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;

使用sql server hierarchyid以正确的顺序对其进行排序如何:

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)
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
| 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/ |
查询1

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)
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
| 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/ |

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)
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
| 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/ |

该查询似乎创建了一个“Adam//Brett”。我认为查询的第一部分需要转换为路径(VARCHAR(MAX),userName)。@openshac。我认为这不会影响排序,但我将
/
移到了我真正想要的位置。很好,EmpLevel字段对我来说真的很有用。