我们经常要用到树形数据,比如:部门、文章栏目、行政区划……,而且有时还需要用到这些数据的全路径,比如:四川省 > 遂宁市 > 船山区。

为了避免每次要使用全路径时都拼接一次,我们可以在数据库增加一个字段来保存全路径,并且使用触发器来生成全路径。

典型的表结构如下:

数据示例如下:

 

由于新增的节点都处于末级,没有子节点,只需要修改新增节点的全路径。

顶层节点的全路径就是节点名称,比如上面的“品质中心”,全路径也是“品质中心”。

非顶层节点的全路径就是上级节点的全路径,加上连接符再加上当前节点名称,比如“FQA”的全路径就是“品质中心 > 品质部 > FQA”。

INSERT触发器代码如下:

ALTER TRIGGER [dbo].[trDeptInsert]
    ON [dbo].[tbDept]
    AFTER INSERT
AS
SET NOCOUNT ON
--连接inserted表得到新增的数据
--连接tbDept表取得上级节点路径,如果是顶层,就没有上级节点,所以需要LEFT JOIN
--如果是顶层,全路径就是节点名称,否则,就是上级节点全路径+连接符+当前节点名称
UPDATE A
SET Path = CASE WHEN A.ParentID = 0 THEN A.Title ELSE B.Path + ' > ' + A.Title END
FROM tbDept A INNER JOIN inserted I ON A.ID = I.ID LEFT JOIN tbDept B ON A.ParentID = B.ID

修改节点后,要做判断,只有修改了节点名称(Title)或者所属上级节点(ParentID),才需要修改全路径,同时,也要修改所有子节点的全路径。

比如将节点“品质部”的名称改为“QA”,那么“品质部”的全路径就应该变为“品质中心 > QA”,下面的“FQA”的全路径也应该变为“品质中心 > QA > FQA”

UPDATE触发器代码如下:

ALTER TRIGGER [dbo].[trDeptUpdate]
    ON [dbo].[tbDept]
    AFTER UPDATE
AS
SET NOCOUNT ON;
--CTE向下递归查出修改了Title或ParentID的节点以及他们的所有后代节点
--连接inserted和deleted表,并判断两个表的Title和ParentID是否发生变化
WITH temp AS (
    SELECT A.ID FROM tbDept A INNER JOIN inserted I ON A.ID = I.ID INNER JOIN deleted D ON I.ID = D.ID
    WHERE I.ParentID <> D.ParentID OR I.Title <> D.Title
    UNION ALL
    SELECT tbDept.ID FROM temp INNER JOIN tbDept ON temp.ID = tbDept.ParentID
)
--CTE数据只能使用一次,所以需要写入临时表,同时增加行号,以便后面遍历
SELECT ID, RowID = ROW_NUMBER() OVER(ORDER BY ID) INTO #TEMP FROM temp
--遍历上面得到的所有节点ID
DECLARE @RowCount int = (SELECT COUNT(*) FROM #TEMP), @RowID int = 1    --行数,行号
WHILE @RowCount >= @RowID
BEGIN
    DECLARE @ID int
    SELECT @ID = ID FROM #TEMP WHERE RowID = @RowID;
    --CTE向上递归得到当前节点及其所有父节点,并增加一个层级字段Level,以便后续按层级顺序拼接路径
    WITH temp AS (
        SELECT Title, ParentID, Level = 0 FROM tbDept WHERE ID = @ID
        UNION ALL
        SELECT A.Title, A.ParentID, Level - 1 FROM tbDept A INNER JOIN temp ON A.ID = temp.ParentID
    )
    --使用FOR XML PATH拼接出节点全路径
    --使用STUFF函数去掉前面多余的连接符号
    --注意使用TYPE和.value('.','NVARCHAR(MAX)'),否则尖括号会被转义,并且value只能小写
    UPDATE tbDept
    SET Path = STUFF((SELECT ' > '+Title FROM temp ORDER BY Level FOR XML PATH(''),TYPE).value('.','NVARCHAR(MAX)'),1,3,'')
    WHERE ID = @ID
    SET @RowID = @RowID + 1
END

 

内容来源于网络如有侵权请私信删除

文章来源: 博客园

原文链接: https://www.cnblogs.com/info-tech/p/17139301.html

你还没有登录,请先登录注册
  • 还没有人评论,欢迎说说您的想法!