删除行后更新层次结构

Update hierarchy after deletion of row

我有一个 table 包含 tree-like 数据(分层设计)。这是一个小样本:

+----+----------+-----------+-------+----------+---------+
| ID | ParentID | Hierarchy | Order | FullPath | Project |
+----+----------+-----------+-------+----------+---------+
|  1 | null     |         1 |     1 | 1        |       1 |
|  2 | null     |         2 |     2 | 2        |       1 |
|  3 | 1        |       1.1 |     1 | 1-3      |       1 |
|  4 | 1        |       1.2 |     2 | 1-4      |       1 |
|  5 | 4        |     1.2.1 |     1 | 1-4-5    |       1 |
|  6 | 2        |       2.1 |     1 | 2-6      |       1 |
|  7 | null     |         3 |     1 | 1        |       2 |
+----+----------+-----------+-------+----------+---------+

Project表示哪个项目拥有层次数据集 ParentID 是 parent 节点的 ID,它在 ID 上有一个外键。 Order 是元素在一个分支中的排名。例如,ID 1, 2 and 7 在同一个节点上,而 3 and 4 在另一个节点上。 FullPath 使用 ID 显示订单(出于系统使用和性能原因)。

Hierarchy是显示给用户的列,它显示层次结构给UI。它会在每次插入、更新和删除后自动计算,这是我遇到的问题。

我在 table 中创建了一个删除元素的程序。它接收要删除的元素的 ID 作为输入并删除它,以及它的 children(如果有)。然后,它重新计算 FullPathOrder Column 。这有效。

当我尝试更新 Hierarchy 列时出现问题。我使用这个程序:

SELECT  T.ID,
        T.ParentID,
        CASE WHEN T.ParentID IS NOT NULL THEN 
            CONCAT(T1.Hierarchy, '.', CAST(T.Order AS NVARCHAR(255))) 
        ELSE 
            CAST(T.Order AS NVARCHAR(255))
        END AS Hierarchy
INTO    #tmp
FROM    t_HierarchyTable T
LEFT JOIN   t_HierarchyTable T1
        ON  T1.ID = T.ParentID
WHERE Project = @Project --Variable to only update the current project for performance
ORDER BY T.FullPath

--Update the table with ID as key on tmp table

当我删除顺序低于其他项目且它们有 children 的项目时,这会失败。 例如,如果我删除项目 3,项目 4 Hierachy 将被更正 (1.1),但它的 child 不会(它将保持在 1.2.1,而它应该是 1.1.1 ).我添加了顺序以确保 parents 首先更新,但没有变化。

我的错误是什么,我真的不知道如何解决这个问题。

我设法用 CTE 更新了层次结构。由于我有订单,我可以根据已经更新的先前分支(父)将其附加到Hierarchy

;WITH CODES(ID, sCode, iLevel) AS 
(
    SELECT 
        T.[ID]                                  AS [ID],
        CONVERT(VARCHAR(8000), T.[Order])       AS [Hierarchy],
        1                                       AS [iLevel]
    FROM 
        [dbo].[data] AS T
    WHERE 
        T.[ParentID] IS NULL

    UNION ALL

    SELECT 
        T.[ID]                                      AS [ID],
        P.[Hierarchy] + IIF(RIGHT(P.[Hierarchy], 1) <> '-', '-', '') + CONVERT(VARCHAR(8000), T.[Order])    AS [Hierarchy],
        P.[iLevel] + 1                              AS [iLevel]
    FROM 
        [dbo].[data] AS T
    INNER JOIN CODES AS P ON 
        P.[ID] = T.[ParentID]
    WHERE
        P.[iLevel] < 100
)
SELECT 
    [ID], [Hierarchy], [iLevel]
INTO
    #CODES
FROM 
    CODES