对于SQL Server来说,构建显示一个树形结构不是一件容易的事情,逻辑构造能力不是它的强项。不过也不是说它没有能力干这个事情,只要换一种思维方式就可以理解它的工作原理。

例如,现在有一张表的内容如下:

CategoryNO CategoryName                                       Parent
---------- -------------------------------------------------- ------
0          ROOT                                               NULL
1          .NET                                               0
2          DataBase                                           0
3          Java                                               0
4          Others                                             0
5          WindowsOS                                          0
6          F#                                                 1
7          C#                                                 1
8          WPF                                                1
9          VB.NET                                             1
10         SQL Server                                         2
11         J2SE                                               3
12         批处理                                              5
13         注册表                                              5
14         SliverLight                                        8
15         基本命令                                            12
16         扩展命令                                            12
17         HKLM                                               13
18         HKCU                                               13
19         DIR                                                15
20         COPY                                               15
21         DEL                                                15
22         IE                                                 5
23         LINQ                                               1
24         C++                                                0

它看上去是多么混乱无序,我们希望它能按如下方式显示,也就是所谓的树形结构:

CategoryNO  CategoryName
----------- --------------------
1           .NET               
6               F#             
7               C#              
8               WPF             
14                  SliverLight 
9               VB.NET          
23              LINQ            
2           DataBase            
10              SQL Server     
3           Java                
11              J2SE            
4           Others              
5           WindowsOS           
12              批处理          
15                  基本命令    
19                      DIR     
20                      COPY    
21                      DEL     
16                  扩展命令    
13              注册表         
17                  HKLM        
18                  HKCU       
22              IE            
24          C++    

至少这样看上去好多了。现在来看看如何实现这个功能。

首先我们需要一个变量来记录当前进入到树形结构的哪个级别,并把它设置为0,表示第一个级别;以及另一个变量来记录当前在对哪条记录操作。

DECLARE @CategoryNO int, @Level int
SET @Level = 0

然后要建立两张临时表,第一张表用来存储待处理记录,第二张表存储最终的结果。关于它们是如何使用的请继续往下看。

CREATE TABLE #TreeViewTemp
(
CategoryNO int NOT NULL,
CategoryName nvarchar(30) NOT NULL,
Parent int NULL,
[Level] int NOT NULL
)
CREATE TABLE #TreeViewResult
(
CategoryNO int NOT NULL,
CategoryName nvarchar(30) NOT NULL
)

接下来向#TreeViewTemp表中插入第一级别的记录。在这里,ROOT记录表示的是根级别,是所有第一级别的父级,最终结果将不包含该记录。注意#TreeViewTemp表中记录了这些记录的级别。

INSERT #TreeViewTemp
SELECT CategoryNO, CategoryName, Parent, @Level
FROM Category
WHERE Parent = 0

再下来,进入一个循环结构。循环结束的条件是#TreeViewTemp表中不再有记录。接下来的内容都是在循环结构中的,BEGIN和END关键字就不写出来了。

WHILE EXISTS (SELECT CategoryNO FROM #TreeViewTemp)

循环的第一条语句,取出#TreeViewTemp中当前级别的第一条记录,并记录下它的CategoryNO(还记得一开始的@CategoryNO和@Level变量吗?)

SELECT TOP(1) @CategoryNO = CategoryNO
FROM #TreeViewTemp
WHERE [Level] = @Level
ORDER BY CategoryNO

如果取不到记录,也就是说临时表中当前级别的记录不存在,那么令@Level变量的值减一,也就是退回上一级别,并继续下一个循环。

IF @@ROWCOUNT = 0
BEGIN
SET @Level = @Level - 1
CONTINUE
END

如果当前级别还有记录,就把这条记录插入到最终结果的表中。插入的时候根据当前级别在名称前面加上空格。

INSERT #TreeViewResult
SELECT CategoryNO, SPACE(4 * @Level) + CategoryName
FROM #TreeViewTemp
WHERE CategoryNO = @CategoryNO

接着找出刚刚那条记录的所有子类别,插入到#TreeViewTemp表中。这里把@Level的值加1再插入到表中,表明这些记录是下一级别的。

INSERT #TreeViewTemp
SELECT CategoryNO, CategoryName, Parent, @Level + 1
FROM Category
WHERE Parent = @CategoryNO

如果这条记录有子类别,那么就使@Level的值加1,进入下一级别。

IF @@ROWCOUNT <> 0
SET @Level = @Level + 1

循环结构中最后一条语句,把#TreeViewTemp中刚刚处理的那条记录删除。

DELETE #TreeViewTemp
WHERE CategoryNO = @CategoryNO

最后一件事,当然是把最终的结果显示出来了。

SELECT CategoryNO, CategoryName FROM #TreeViewResult

最最后的,把临时表删除。

DROP TABLE #TreeViewTemp
DROP TABLE #TreeViewResult

好了,构建树形结构的基本框架就是这样,可以在这个基础上作些修改以适应不同的需求。

我不知道以上说明是否能让大家明白这个逻辑,甚至我自己也说不清楚,它实在是比较复杂……

这个方法有一个缺点,就是使用了临时表。由于临时表的数据是存储在硬盘中的,所以整个过程的速度会有影响。

在最后把整个过程的代码整合在一起:


DECLARE @CategoryNO int, @Level int
SET @Level = 0
CREATE TABLE #TreeViewTemp
(
CategoryNO int NOT NULL,
CategoryName nvarchar(30) NOT NULL,
Parent int NULL,
[Level] int NOT NULL
)
CREATE TABLE #TreeViewResult
(
CategoryNO int NOT NULL,
CategoryName nvarchar(30) NOT NULL
)
INSERT #TreeViewTemp
SELECT CategoryNO, CategoryName, Parent, @Level
FROM Category
WHERE Parent = 0
WHILE EXISTS (SELECT CategoryNO FROM #TreeViewTemp)
BEGIN
SELECT TOP(1) @CategoryNO = CategoryNO
FROM #TreeViewTemp
WHERE [Level] = @Level
ORDER BY CategoryNO
IF @@ROWCOUNT = 0
BEGIN
SET @Level = @Level - 1
CONTINUE
END
INSERT #TreeViewResult
SELECT CategoryNO, SPACE(4 * @Level) + CategoryName
FROM #TreeViewTemp
WHERE CategoryNO = @CategoryNO
INSERT #TreeViewTemp
SELECT CategoryNO, CategoryName, Parent, @Level + 1
FROM Category
WHERE Parent = @CategoryNO
IF @@ROWCOUNT <> 0
SET @Level = @Level + 1
DELETE #TreeViewTemp
WHERE CategoryNO = @CategoryNO
END
SELECT CategoryNO, CategoryName FROM #TreeViewResult
DROP TABLE #TreeViewTemp
DROP TABLE #TreeViewResult

[SQL Server]树形结构的创建的更多相关文章

  1. SQL Server 索引结构及其使用(一)

    转载:SQL Server 索引结构及其使用(一) 作者:freedk 一.深入浅出理解索引结构 实际上,您可以把索引理解为一种特殊的目录.微软的SQL SERVER提供了两种索引:聚集索引(clus ...

  2. SQL Server 索引结构及其使用(一)[转]

    SQL Server 索引结构及其使用(一) 作者:freedk 一.深入浅出理解索引结构 实际上,您可以把索引理解为一种特殊的目录.微软的SQL SERVER提供了两种索引:聚集索引(cluster ...

  3. SQL server 表结构转Oracle SQL脚本

    SQL server 表结构转Oracle SQL脚本 /****** Object: StoredProcedure [dbo].[getOracle] Script Date: 2019/7/25 ...

  4. SQL server 表中如何创建索引?

    SQL server 表中如何创建索引?看个示例,你就会了 use master goif db_id(N'zhangxu')is not nulldrop database zhangxugocre ...

  5. 修改SQL Server数据库表的创建时间最简单最直接有效的方法

    说明:这篇文章是几年前我发布在网易博客当中的原创文章,但由于网易博客现在要停止运营了,所以我就把这篇文章搬了过来,因为这种操作方式是通用的,即使是对现在最新的SQL Server数据库里面的操作也是一 ...

  6. SQL Server 2017 SELECT…INTO 创建的新表指定到文件组

    原文:SQL Server 2017 SELECT-INTO 创建的新表指定到文件组 SELECT-INTO 在 SQL Server 中也是常见的一个功能,过去用此方法创建的新表只能存储到默认的文件 ...

  7. 【随记】安装SQL Server 2008 R2 提示创建usersettings/microsoft.sqlserver.configuration.landingpage.properties.se

    在安装SQL Server 2008 R2 提示创建usersettings/microsoft.sqlserver.configuration.landingpage.properties.se.. ...

  8. SQL Server查询性能优化——创建索引原则(一)

    索引是什么?索引是提高查询性能的一个重要工具,索引就是把查询语句所需要的少量数据添加到索引分页中,这样访问数据时只要访问少数索引的分页 就可以.但是索引对于提高查询性能也不是万能的,也不是建立越多的索 ...

  9. SQL Server 查询性能优化——创建索引原则(一)(转载)

    索引是什么?索引是提高查询性能的一个重要工具,索引就是把查询语句所需要的少量数据添加到索引分页中,这样访问数据时只要访问少数索引的分页就可以.但是索引对于提高查询性能也不是万能的,也不是建立越多的索引 ...

随机推荐

  1. RTB广告展示分步说明

    原文:http://contest.ipinyou.com/cn/manual.shtml RTB (Real Time Bidding, 实时竞价) 是近年来计算广告领域最激动人心的进展之一. 它增 ...

  2. 利用 Composer 完善自己的 PHP 框架(一)——视图装载

    本教程示例代码见 https://github.com/johnlui/My-First-Framework-based-on-Composer 回顾 经过了上一个 系列教程  <利用 Comp ...

  3. PHP读书笔记(3)-常量

    什么是常量 什么是常量?常量可以理解为值不变的量 :或者是常量值被定义后,在脚本的其他任何地方都不可以被改变.手册上是这么定义PHP的常量:常量是一个简单值的标识符(名字).如同其名称所暗示的,在脚本 ...

  4. Recovery启动流程(3)--recovery.cpp分析

    转载请注明来源:cuixiaolei的技术博客 这篇文章主要通过分析高通recovery目录下的recovery.cpp源码,对recovery启动流程有一个宏观的了解.MTK和高通的recovery ...

  5. cocos2d-x——在一个cpp中展示多个场景

    //20秒后自动运行下一个场景 runAction( CCSequence::create(CCDelayTime::create(20.0f), CCCallFunc::create(this, c ...

  6. Scala的基本语法总结

    Scala的函数: 目前博客园中的代码编辑器中还不支持Scala语言....用的Java代码的存储方式 object TestScala { def main(args: Array[String]) ...

  7. 关于Linux的总结(二)

    主要内容 Linux 安装 常用命令 VI编辑器的使用 远程登录 主机名的设置 IP的设置 防火墙的设置 用户和组账户管理 文件权限管理 RPM软件包管理 软件的安装 Jdk,tomcat, ecli ...

  8. 为dedecms v5.7的ckeditor添加jwplayer插件

    dedecms v5.7的默认编辑器是ckeditor,不过用的是php版本的,默认的工具栏不在config.js里面配置,而是在ckeditor.inc.php里面配置,默认的工具栏是$toolba ...

  9. 《跨终端Web》读书笔记

    跨终端的Web成为了趋势,而这本书就是讲了在这种趋势下进行开发的常见问题及其解决方案,可能是限于篇幅,每个方面都没有展开细说,但这是这样让本书干货满满,几乎没有一句废话. 下面是一些笔记. Web的本 ...

  10. WM_NCCALCSIZE消息处理详解

    [前言]指定应用程序的标题高度和边框的宽度的方法有很多种.其中最普遍的方法有下面的两种:第一种:创建没有标题栏应用程序,在客户区让出一部分空间用一幅图片画一个标题栏,让人“误认为”是标题栏.第二种:处 ...