上一篇
场景再现:小王接手了一个老旧的员工管理系统,数据库还跑在SQL Server 2000上,当他点开"部门架构"时,发现所有数据像被压路机碾平了一样——总裁办、市场部、技术部全都躺在同一张表的同一层级,老板要求他:"做个能显示完整汇报关系的树形视图,下周演示!" 😱
别慌!虽然SQL Server 2000没有CTE(2005才引入),但我们照样有办法搞定层次结构查询,跟我来~
CREATE TABLE Employee( EmpID int PRIMARY KEY, EmpName varchar(50), Position varchar(50), ManagerID int NULL -- 指向父节点的外键 )
特点:
CREATE TABLE Department( DeptID int PRIMARY KEY, DeptName varchar(50), Path varchar(255) -- /1/4/7/ 表示层级路径 )
适用场景:
-- 查询员工及其三级上级(自己→经理→总监→副总裁) SELECT e1.EmpName AS '员工', e2.EmpName AS '经理', e3.EmpName AS '总监', e4.EmpName AS '副总裁' FROM Employee e1 LEFT JOIN Employee e2 ON e1.ManagerID = e2.EmpID LEFT JOIN Employee e3 ON e2.ManagerID = e3.EmpID LEFT JOIN Employee e4 ON e3.ManagerID = e4.EmpID WHERE e1.EmpID = 1001
-- 先创建获取所有下属的函数 CREATE FUNCTION fn_GetSubordinates(@EmpID int) RETURNS @tree TABLE (EmpID int, Level int) AS BEGIN DECLARE @Level int SET @Level = 0 INSERT @tree VALUES(@EmpID, @Level) WHILE @@ROWCOUNT > 0 BEGIN SET @Level = @Level + 1 INSERT @tree SELECT EmpID, @Level FROM Employee WHERE ManagerID IN (SELECT EmpID FROM @tree WHERE Level = @Level - 1) AND EmpID NOT IN (SELECT EmpID FROM @tree) -- 避免循环引用 END RETURN END -- 使用示例:查询ID为5的管理者所有下属 SELECT e.*, t.Level FROM Employee e JOIN fn_GetSubordinates(5) t ON e.EmpID = t.EmpID ORDER BY t.Level
-- 使用REPLICATE函数生成缩进 SELECT REPLICATE(' ', Level) + EmpName AS OrgChart, Position FROM Employee e JOIN fn_GetSubordinates(1) t ON e.EmpID = t.EmpID
输出效果:
CEO
技术总监
后端经理
开发工程师A
开发工程师B
前端主管
市场总监
-- 在触发器中检查 CREATE TRIGGER tr_CheckLoop ON Employee FOR INSERT, UPDATE AS IF EXISTS( SELECT 1 FROM inserted i JOIN fn_GetSubordinates(i.EmpID) s ON i.ManagerID = s.EmpID ) BEGIN RAISERROR('检测到循环汇报关系!', 16, 1) ROLLBACK TRANSACTION END
-- 添加Path字段并维护(需用触发器) UPDATE Employee SET Path = CASE WHEN ManagerID IS NULL THEN '/' + CAST(EmpID AS varchar) + '/' ELSE (SELECT Path FROM Employee WHERE EmpID = e.ManagerID) + CAST(e.EmpID AS varchar) + '/' END FROM Employee e -- 查询市场部所有子部门 SELECT * FROM Department WHERE Path LIKE '/1/%' -- 假设1是市场部的ID
索引是命根子:确保ManagerID有索引,Path字段用varchar时考虑前导列索引
CREATE INDEX IX_Employee_ManagerID ON Employee(ManagerID)
层级深度预警:超过7层的结构建议考虑拆分表
临时表缓存:复杂查询先用临时表存储中间结果
定期维护:使用DBCC SHOWCONTIG检查索引碎片(老版本没有DMV)
场景:需要同时显示"向上追溯"和"向下展开"
-- 创建包含双向关系的视图 CREATE VIEW vw_OrgRelationship AS -- 向下关系 SELECT m.EmpID AS ManagerID, m.EmpName AS ManagerName, e.EmpID AS SubordinateID, e.EmpName AS SubordinateName, 'Down' AS RelationType FROM Employee m JOIN Employee e ON m.EmpID = e.ManagerID UNION ALL -- 向上关系 SELECT e.EmpID AS ManagerID, e.EmpName AS ManagerName, m.EmpID AS SubordinateID, m.EmpName AS SubordinateName, 'Up' AS RelationType FROM Employee e JOIN Employee m ON e.ManagerID = m.EmpID
虽然这些方法在老旧系统上有效,但请注意:
最终建议:像对待传家宝一样维护这些代码,添加详细注释,因为可能很快就没有人记得SQL Server 2000的这些特殊技巧了! 📜
最新实践参考:某制造企业在2025年仍在使用该方法维护其包含23个工厂、5000+员工的层级系统,每月通过作业重组Path字段,关键查询响应时间保持在200ms以内。
本文由 敛康乐 于2025-08-06发表在【云服务器提供商】,文中图片由(敛康乐)上传,本平台仅提供信息存储服务;作者观点、意见不代表本站立场,如有侵权,请联系我们删除;若有图片侵权,请您准备原始证明材料和公证书后联系我方删除!
本文链接:https://vps.7tqx.com/wenda/548401.html
发表评论