您如何动态地为分层表中的每一行分配唯一代码?

时间:2019-07-08 08:22:19

标签: sql-server tsql

我的桌子。

表1

Id  ParentId Name   Code
1   Null     John  
2   1        Harry
3   1        Mary
4   2        Emma
5   2        Kyle
6   4        Robert
7   Null     Rohit

我想为每个人分配以下格式的唯一层次代码

需要输出

 Id   ParentId   Name      Code
    1   Null     John     1
    2   1        Harry    1.1
    3   1        Mary     1.2
    4   2        Emma     1.1.1
    5   2        Kyle     1.1.2
    6   4        Robert   1.1.1.1
    7  Null      Rohit    2

以此类推。

1 个答案:

答案 0 :(得分:1)

我希望我正确无误...

您可以将递归CTE与ROW_NUMBER()一起使用来创建代码。

DECLARE @dummy TABLE(Id INT,ParentId INT,[Name] VARCHAR(100));
INSERT INTO @dummy(Id,ParentId,[Name]) VALUES
 (1,Null,'John')  
,(2,1   ,'Harry')
,(3,1   ,'Mary')
,(4,2   ,'Emma')
,(5,2   ,'Kyle')
,(6,4   ,'Robert')
,(7,Null,'Rohit');

WITH recCTE AS
(
    SELECT Id,ParentId,[Name]
          ,CONCAT(N'.',CAST(ROW_NUMBER() OVER(ORDER BY Id) AS NVARCHAR(MAX))) AS Code 
    FROM @dummy WHERE ParentId IS NULL

    UNION ALL
    SELECT d.Id,d.ParentId,d.[Name]
          ,CONCAT(r.Code,N'.', ROW_NUMBER() OVER(ORDER BY d.Id)) 
    FROM @dummy d
    INNER JOIN recCTE r ON d.ParentId=r.Id
)
SELECT Id,ParentId,[Name] 
      ,STUFF(Code,1,1,'') AS Code
FROM RecCTE;

简而言之:

我们用ParentId IS NULL挑选行,并给它们一个运行号。
现在,我们遍历它们(实际上是一个隐藏的RBAR ),并再次给他们的孩子一个连续的号码。
我们会一直这样做,直到没有剩下任何东西为止。 最后的SELECT需要一个STUFF才能摆脱第一个点。

使用这样的扩展名,您可以创建字母数字可排序代码:

WITH recCTE AS
(
    SELECT Id,ParentId,[Name]
          ,CONCAT(N'.',CAST(ROW_NUMBER() OVER(ORDER BY Id) AS NVARCHAR(MAX))) AS Code 
          ,CONCAT(N'000',CAST(ROW_NUMBER() OVER(ORDER BY Id) AS NVARCHAR(MAX))) AS Code2 
    FROM @dummy WHERE ParentId IS NULL

    UNION ALL
    SELECT d.Id,d.ParentId,d.[Name]
          ,CONCAT(r.Code,N'.', ROW_NUMBER() OVER(ORDER BY d.Id)) 
          ,CONCAT(r.Code2,RIGHT(CONCAT('0000',ROW_NUMBER() OVER(ORDER BY d.Id)),4))
    FROM @dummy d
    INNER JOIN recCTE r ON d.ParentId=r.Id
)
SELECT Id,ParentId,[Name] 
      ,STUFF(Code,1,1,'') AS Code
      ,Code2
FROM RecCTE
ORDER BY Code2;