博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SQL Server 存储层级数据实现无限级分类
阅读量:4128 次
发布时间:2019-05-25

本文共 2509 字,大约阅读时间需要 8 分钟。

由于数据库存储的数据都是以平面方式存储,所以目前大部分论坛和其他程序都是用递归来展现层次数据的,如果分类的层次十分深的话那么使用的递归次数相当可观,对性能的影响也非常大。最近要做一个分类信息的平台就遇到这个问题了,那么如何实现快速的展现分层数据呢?,这个算法目前唯一的问题就是尚未实现分类排序,我们可以通过右值的反向排序实现先入先出的排序。在这里我们需要了解的是如何用 SQL Server 来实现,我们就以省市县数据库为例来实现:

如图所示我们将一个树节点的左右各编上号码,就可以看出一些规律,山西的左右值为(8,17),那么所有左值大于8,右值小于17的节点都是属于山西的子节点。稷山先的左右值为(14,15),那么他的所有父节点就是左值小于14,右值大于15的节点,怎么样,用这个方法实现的无限级分类性能绝对是顶呱呱的。一次查询就可以查出属于某个节点的数据以及他子节点的数据。这个算是我见过性能最高的无限级分类算法。其他算法跟这个对比基本没有任何优势。

我们先建立一个数据表,结构如下图(LID 为左值,RID 为右值,Tree 为节点深度,Name 和 ID 就不多说了,节点的索引和名称)

我们可以使用下面的存储过程来获得一个节点和其子节点:

CREATE PROCEDURE CLSP_ZoneSelect   
(  
    @Root INT,  
    @Tree INT 
)  
AS 
    SELECT Z.ID,Z.Tree,Z.Name  
    FROM CL_ZoneData AS Z,CL_ZoneData AS P  
    WHERE   P.ID = @Root  
         AND Z.LID >= P.LID AND Z.RID <= P.RID  
            AND (@Tree = 0 OR Z.Tree <= P.Tree + @Tree)  
    ORDER BY Z.LID ASC 
GO 

我们可以用下面这个存储过程来在一个节点下插入新的子节点:

CREATE PROCEDURE CLSP_ZoneInsert   
(  
    @Root INT,  
    @Name NVARCHAR(50)  
)  
AS 
    DECLARE @RID AS INT,@NID AS INT,@Tree AS INT 
 
    SET @RID = 1  
    SET @NID = 0  
    SET @Tree = 1  
 
    IF @Root = 0  
    BEGIN 
        SELECT TOP 1 @RID = RID + 1  
        FROM CL_CateData ORDER BY RID DESC 
    END 
    ELSE 
    BEGIN 
        SELECT @RID = RID, @Tree = Tree + 1  
        FROM CL_ZoneData WHERE ID = @Root  
    END 
 
    IF @Root = 0 OR @RID > 1  
    BEGIN 
        UPDATE CL_ZoneData SET RID = RID + 2 WHERE RID >= @RID  
        UPDATE CL_ZoneData SET LID = LID + 2 WHERE LID > @RID  
 
        INSERT INTO CL_ZoneData(LID,RID,Tree,Name)  
        VALUES (@RID,@RID + 1,@Tree,@Name)  
 
        SET @NID = SCOPE_IDENTITY()  
    END 
    SELECT @NID  
GO 

删除一个节点可以用下面的存储过程:

CREATE PROCEDURE CLSP_ZoneDelete   
(  
    @ID INT 
)   
AS 
    DECLARE @LID AS INT, @RID AS INT, @WID AS INT, @DID AS INT 
    SET @DID = 0  
    SELECT @DID = ID, @LID = LID, @RID = RID, @WID = RID - LID + 1 FROM CL_ZoneData WHERE ID = @ID  
    IF @DID != 0  
    BEGIN 
        DELETE FROM CL_ZoneData WHERE LID BETWEEN @LID AND @RID  
        UPDATE CL_ZoneData SET RID = RID - @WID WHERE RID > @RID  
        UPDATE CL_ZoneData SET LID = LID - @WID WHERE LID > @RID  
    END 
    SELECT @DID  
GO  
这个方法,节点排序已经可以了。节点移动比较麻烦,不过可以曲线救国,在需要移动到的节点建立一个新的。然后把子节点和数据都移动过去,再删除现有的节点。
 
引用:

转载地址:http://wqzvi.baihongyu.com/

你可能感兴趣的文章
Spring框架的ImportSelector到底可以干嘛
查看>>
Mysql中下划线问题
查看>>
微信小程序中使用npm过程中提示:npm WARN saveError ENOENT: no such file or directory
查看>>
Xcode 11 报错,提示libstdc++.6 缺失,解决方案
查看>>
idea的安装以及简单使用
查看>>
Windows mysql 安装
查看>>
python循环语句与C语言的区别
查看>>
Vue项目中使用img图片和background背景图的使用方法
查看>>
vue 项目中图片选择路径位置static 或 assets区别
查看>>
vue项目打包后无法运行报错空白页面
查看>>
Vue 解决部署到服务器后或者build之后Element UI图标不显示问题(404错误)
查看>>
element-ui全局自定义主题
查看>>
facebook库runtime.js
查看>>
vue2.* 中 使用socket.io
查看>>
openlayers安装引用
查看>>
js报错显示subString/subStr is not a function
查看>>
高德地图js API实现鼠标悬浮于点标记时弹出信息窗体显示详情,点击点标记放大地图操作
查看>>
初始化VUE项目报错
查看>>
vue项目使用安装sass
查看>>
HTTP和HttpServletRequest 要点
查看>>