SQL Server通过递归CTE获取路径

时间:2018-06-17 04:21:32

标签: sql-server common-table-expression

我希望获得每个部门的路径,格式为1.1,1.2等。 这是我的部门表:

id  name    parentId
--------------------
1   Dep 1   0
2   Dep 2   1
3   Dep 3   0
4   Dep 4   1
5   Dep 5   4
6   Dep 6   2

这是我的递归CTE,从根部开始给我父母和孩子一张平台。

WITH recursiveCte (parentId, id, name, Level)
AS
(
    -- Anchor member definition
    SELECT 
        d.parentId, d.id, d.name, 
        0 AS Level
    FROM
        Department AS d
    WHERE 
        parentId = 0 

    UNION ALL

    -- Recursive member definition
    SELECT 
        d.parentId, d.id, d.name,
        Level + 1
    FROM 
        Department AS d
    INNER JOIN 
        recursiveCte AS r ON d.parentId = r.id
)
-- Statement that executes the CTE
SELECT parentId,id, name, Level
FROM recursiveCte 
ORDER BY id

目前的结果:

parentId    id  name    Level
-------------------------------
0           1   Dep 1   0
1           2   Dep 2   1
0           3   Dep 3   0
1           4   Dep 4   1
4           5   Dep 5   2
2           6   Dep 6   2

期望的结果:

parentId    id  name    Level   Path
--------------------------------------
0           1   Dep 1   0       1  
1           2   Dep 2   1       1.1 
2           6   Dep 6   2       1.1.1
1           4   Dep 4   1       1.2
4           5   Dep 5   2       1.2.1 
0           3   Dep 3   0       2 

感谢。

1 个答案:

答案 0 :(得分:1)

这是一个有效的解决方案。很难用文字描述为什么这样有效,所以我建议拆开查询,看看它是如何工作的。基本上,我们递归地构建您想要查看的路径字符串,使用ROW_NUMBER跟踪每个新路径添加所属的特定父级。

recursiveCte (parentId, id, name, Level, Path, FullPath) AS (
    SELECT d.parentId, d.id, d.name, 0 AS Level,
        CAST(ROW_NUMBER() OVER (ORDER BY d.id) AS nvarchar(max)),
        RIGHT('000' + CAST(ROW_NUMBER() OVER (ORDER BY d.id) AS nvarchar(max)), 3)
    FROM Department AS d
    WHERE parentId = 0 

    UNION ALL

    SELECT d.parentId, d.id, d.name, r.Level + 1,
        r.Path + '.' +
        CAST(ROW_NUMBER() OVER (PARTITION BY r.Level ORDER BY d.id) AS nvarchar(max)),
        r.FullPath + '.' + RIGHT('000' + CAST(ROW_NUMBER() OVER
            (PARTITION BY r.Level ORDER BY d.id) AS nvarchar(max)), 3)
    FROM Department AS d
    INNER JOIN recursiveCte AS r
        ON d.parentId = r.id
)

SELECT parentId, id, name, Level, Path, FullPath
FROM recursiveCte
ORDER BY FullPath;

enter image description here

Demo

修改

我稍微编辑了我的原始答案,以便它现在使用固定宽度版本对路径字符串进行排序,即每个数字的固定宽度为3位数。这意味着001将始终在010之前排序,这是我们想要的行为。