关于SQLServer2005的学习笔记——树形结构问题
2010-01-29 12:40
435 查看
关于解决树形目录是每种数据库
或大多数开发人员都要面对的问题,在这一点上
Oracle
走的跟前线一些,从
9i
起便提供了
connect by
进行了支持,
10g
又增强了相关语法;在
SQLServer2005
中,强大的
CTE
功能也提供了相应的解决方案,此外提供的表函数功能也给出了另外一种解决思路。
从功能上讲的话,表函数方式更为灵活一些,毕竟基于过程的结构方式更容易实现负责的业务逻辑;但递归
CTE
构造起来更为清晰一些。
该文起源于《
Microsoft SQL
Server
2005
技术内幕:
T-SQL
查询》,但与文中所述不尽相同。
首先构建一个标准的树形结构的员工表
--
让我们先来看看
Oracle
是如何实现的吧
--
构建递归
CTE
,也可以灵活获取满足不同级别的上下级节点
--
通过表函数方式返回相关节点
或大多数开发人员都要面对的问题,在这一点上
Oracle
走的跟前线一些,从
9i
起便提供了
connect by
进行了支持,
10g
又增强了相关语法;在
SQLServer2005
中,强大的
CTE
功能也提供了相应的解决方案,此外提供的表函数功能也给出了另外一种解决思路。
从功能上讲的话,表函数方式更为灵活一些,毕竟基于过程的结构方式更容易实现负责的业务逻辑;但递归
CTE
构造起来更为清晰一些。
该文起源于《
Microsoft SQL
Server
2005
技术内幕:
T-SQL
查询》,但与文中所述不尽相同。
首先构建一个标准的树形结构的员工表
CREATE TABLE Employees ( EmpID INT, MgrID INT, EmpName VARCHAR(25), Salary MONEY, CHECK(EmpID<>MgrID) ); GO INSERT INTO Employees VALUES(1,NULL,'David',10000); INSERT INTO Employees VALUES(2,1,'Eitan',7000); INSERT INTO Employees VALUES(3,1,'Ina',7500); INSERT INTO Employees VALUES(4,2,'Seraph',5000); INSERT INTO Employees VALUES(5,2,'Jiru',5500); INSERT INTO Employees VALUES(6,2,'Steve',4500); INSERT INTO Employees VALUES(7,3,'Aaron',5000); INSERT INTO Employees VALUES(8,5,'Lilach',3500); INSERT INTO Employees VALUES(9,7,'Rita',3000); INSERT INTO Employees VALUES(10,5,'Sean',3000); INSERT INTO Employees VALUES(11,7,'Gabriel',3000); INSERT INTO Employees VALUES(12,9,'Emilia',2000); INSERT INTO Employees VALUES(13,9,'Michael',2000); INSERT INTO Employees VALUES(14,9,'Didi',1500); |
让我们先来看看
Oracle
是如何实现的吧
-- 获取所有相关员工信息,并构建其级别和相应的结构指向 SELECT EmpID,MgrID,EmpName,Salary,Level,sys_connect_by_path(NVL(EmpID,'0'),'->') FROM Employees CONNECT BY PRIOR EmpID=MgrID START WITH MgrID IS NULL -- 获取员工的所有下级节点 SELECT EmpID,MgrID,EmpName,Salary,Level FROM Employees CONNECT BY PRIOR EmpID=MgrID START WITH EmpID=9 -- 获取员工的所有上级节点 SELECT EmpID,MgrID,EmpName,Salary,Level FROM Employees CONNECT BY PRIOR MgrID=EmpID START WITH EmpID=14 |
构建递归
CTE
,也可以灵活获取满足不同级别的上下级节点
WITH EmployeeTree AS ( SELECT EmpID,MgrID,EmpName,Salary, 0 AS Level, CAST(CASE WHEN MgrID IS NULL THEN 'Root' END AS VARCHAR(50)) MgrList FROM Employees WHERE MgrID IS NULL -- 此处亦可修改为 MgrID=@Root ,即传入的节点,即可得到想要的节点内容 UNION ALL SELECT C.EmpID,C.MgrID,C.EmpName,C.Salary, P.Level+1 AS Level, CAST(CAST(P.MgrList AS VARCHAR(50))+'->'+CAST(C.EmpID AS VARCHAR(10)) AS VARCHAR(50)) MgrList FROM EmployeeTree P,Employees C WHERE C.MgrID=P.EmpID --AND P.Level<2 设定相关级别 ) -- 所有员工 SELECT * FROM EmployeeTree -- 求某员工上级 SELECT * FROM EmployeeTree WHERE CHARINDEX(MgrList,(SELECT MgrList FROM EmployeeTree WHERE EmpID=7))>0 -- 求某员工下级 SELECT * FROM EmployeeTree WHERE MgrList LIKE (SELECT MgrList FROM EmployeeTree WHERE EmpID=7)+'%' -- 求某员工下级并且符合相应级数的 SELECT * FROM EmployeeTree WHERE MgrList LIKE (SELECT MgrList FROM EmployeeTree WHERE EmpID=7)+'%' AND Level<=(SELECT Level FROM EmployeeTree WHERE EmpID=7)+1 |
通过表函数方式返回相关节点
CREATE FUNCTION fn_GetEmployeeTree(@root AS INT) RETURNS @Subs TABLE ( EmpID INT, Level INT ) AS BEGIN DECLARE @Level AS INT; SET @Level=0; INSERT INTO @Subs(EmpID,Level) SELECT EmpID,@Level FROM Employees WHERE EmpID=@root; WHILE @@rowcount>0 BEGIN SET @Level=@Level+1; INSERT INTO @Subs(EmpID,Level) SELECT C.EmpID,@Level FROM @SubS AS P JOIN Employees AS C ON P.Level=@Level-1 AND C.MgrID=P.EmpID END RETURN; END SELECT * FROM fn_GetEmployeeTree(1) |
相关文章推荐
- 关于SQLServer2005的学习笔记——树形结构问题
- 关于SQLServer2005的学习笔记——生日问题
- PE结构学习笔记--关于AddressOfEntryPoint位置在文件中怎么确定问题
- 关于SQLServer2005的学习笔记——统计学自动分组问题
- 关于SQLServer2005的学习笔记——统计学自动分组问题
- PE结构学习笔记--关于AddressOfEntryPoint位置在文件中怎么确定问题
- 关于SQLServer2005的学习笔记——生日问题
- 关于SQLServer2005的学习笔记——多触发器执行问题
- 关于SQLServer2005的学习笔记——生日问题
- 关于SQLServer2005的学习笔记——多触发器执行问题
- 关于SQLServer2005的学习笔记——统计学自动分组问题
- 关于SQLServer2005 的学习笔记(二)——体系结构一
- 【学习笔记】一个关于在时间轴上编程的问题
- 关于asp.net 2.0 入门学习之“GlobalResources与Callback问题”的笔记
- sqlserver -- 学习笔记(三)解决php连接sqlserver2005视图时显示“异类查询要求为连接设置 ANSI_NULLS 和 ANSI_WARNINGS 选项”的问题
- [openCV学习笔记]——关于waitKey(0)不起作用的问题
- 关于SQLServer2005的学习笔记(二)——体系结构(一)
- 摄像机标定学习笔记(12)关于相机标定的问题答复网友(转载)
- Go学习笔记:关于golang.org/x包问题
- PHP7 学习笔记(三)关于PHP7如何安装调试工具Xdebug扩展以及Zephir的问题