【问题标题】:SQL Server get path with recursive CTESQL Server 使用递归 CTE 获取路径
【发布时间】:2018-06-17 04:21:31
【问题描述】:

我想用这种格式 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 

谢谢。

【问题讨论】:

    标签: sql-server common-table-expression


    【解决方案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;
    

    Demo

    编辑:

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

    【讨论】:

    • 我会稍微修改一下代码,因为路径 10 会在路径 2 之前,因为它是一个字符串。
    • @lory 我更新了我的答案,以便它现在使用路径字符串的固定宽度版本来进行排序。在这种情况下,我假设您不会有任何大于 999 的路径元素,但您可以根据需要轻松修改它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-23
    • 2014-05-19
    • 2012-12-25
    • 1970-01-01
    • 2018-03-30
    • 2020-06-08
    相关资源
    最近更新 更多