前言
前几天朋友问我,关于SQLServer数据库中对树形结构的表数据统计问题,需求大致如下:
分类表(递归数据),A的子分类是B,B的子分类是C……分类关系不间断,A为第一层,B为第二层,C为第三层……需要统计“每个分类所在的层数”、“子分类的总数”和“子分类的层数”。
解决思路:
创建示例表结构,代码如下:
-- 分类示例表 create table temp_class ( classId int primary key identity(1,1), -- 分类ID,主键,递增 className nvarchar(50), -- 分类名称 pcId int default 0, -- 父级分类ID,0表示最顶层 uLevel int, -- 层数 nextUCount int, -- 子分类的总数 nextLevelCount int -- 子分类的层数 ); -- 层数字段添加索引 -- create index ind_tempClass_uLevel on temp_class(uLevel); -- 添加测试数据。。。。。。
步骤一:每个分类所在的层数
根据树形数据结构的规律,在统计层数时,需要从最顶层向下累计,代码如下:
-- 1、更新层数(pcId=0 表示第一层) -- 更新最顶层 declare @i int=1; -- 第一层 update temp_class set uLevel=@i where pcId=0; while(1=1) begin if(not exists(select top 1 1 from temp_class a where exists(select top 1 1 from temp_class b where b.uLevel=@i and b.classId=a.pcId))) break; -- 无下层数据,跳出循环 -- 更新下一层 update a set a.uLevel=@i+1 from temp_class a where exists(select top 1 1 from temp_class b where b.uLevel=@i and b.classId=a.pcId); -- 增加一层 set @i=@i+1; end;
步骤二:子分类的总数
在第一步中,已经统计出了分类的层数,在统计每个分类的子分类个数时,就从最底层统计起来,本层子分类的个数就等于下一层中子分类的个数之和加上下一层的分类数量,代码如下:
-- 2、更新子分类的总数 -- 获取最低层分类(最大的层数) declare @maxLevel int=1; select @maxLevel=MAX(uLevel) from temp_class; -- 更新最底层的子分类总数为 0 update temp_class set nextUCount=0 where uLevel=@maxLevel; -- 从最底层向上累计子分类总数 while(1=1) begin set @maxLevel=@maxLevel-1; if(@maxLevel<=0) -- 层数走完,退出 break; -- 更新上一层的子分类的总数 update a set a.nextUCount=isnull(b.nextUCount,0) from temp_class a left join -- 父级(本层)分类的个数=下一层中子分类的个数之和+下一层的分类数量 (select pcId,SUM(nextUCount)+COUNT(classId) nextUCount from temp_class where uLevel=@maxLevel+1 group by pcId) b on a.classId=b.pcId where a.uLevel=@maxLevel; end;
步骤三:子分类的层数
在第一步中,已经统计出了分类的层数,在统计每个分类的子分类层数时,就从最底层统计起来,本层子分类的层数就等于下一层中子分类的层数最大值加上一层,代码如下:
-- 3、更新子分类的层数 -- 获取最低层子分类(最大的层数) declare @maxLevel int=1; select @maxLevel=MAX(uLevel) from temp_class; -- 更新最底层的子分类层数为 0 update temp_class set nextLevelCount=0 where uLevel=@maxLevel; -- 从最底层向上累计层数 while(1=1) begin set @maxLevel=@maxLevel-1; if(@maxLevel<=0) -- 层数走完,退出 break; -- 更新上一层的子分类层数 update a set a.nextLevelCount=ISNULL(b.nextLevelCount,0) from temp_class a left join -- 父级(本层)分类的层数=下一层中子分类的最大层数+1(当前子分类为 1 层) (select pcId,(MAX(nextLevelCount)+1) as nextLevelCount from temp_class where uLevel=@maxLevel+1 group by pcId) b on a.classId=b.pcId where a.uLevel=@maxLevel; end;
查询结果:
后言
该随笔仅当个人笔记所用,路过的大神如有好的建议,还请赐教,菜鸟再此感激不尽!