sql多级分类汇总实现介绍

据库结构如下
类别表
分类id 上级分类id 分类名称 分类级别 排序值

 代码如下 复制代码
id parentid categoryname categorylevel ordering
1   null      c1            1           1
2    1        c11           2           1
3    1        c12           2           2
4    1        c13           2           3
5    1        c14           2           4
6    2        c111          3           1
7    2        c112          3           2

然后 内容表是
内容id 类别id .........

 代码如下 复制代码
id categoryid .........
1    1       ........
2    4       ........
3    5       ........

这样处理的弊端是:如果数据量大,子分类很多,达到4级以上,这方法处理极端占用数据库连接池
对性能影响很大。

如果用SQL下面的CTE递归处理的话,一次性就能把结果给查询出来,而且性能很不错
比用程序处理(数据量很大的情况),临时表性能更好,更方便 

 代码如下 复制代码
with area as(
select *,id px,cast(id as nvarchar(4000)) px2 from region where parentid=0
union all
select a.*,b.px,b.px2+ltrim(a.region_id) from region a join area b on a.parentid=b.id
)select * from area order by px,px2

可以查询出结果—-所有分类及相应分类下子分类

 代码如下 复制代码
id title parentid
1 广东省 0
2 广州 1
3 白云区 2
4 深圳 1
5 湖南省 0
6 长沙 5
7 株洲 5
 代码如下 复制代码

with area as(
select * from region where parentid=1
union all
select a.* from region a join area b on a.parentid=b.id
)select * from area

可以查询出结果—-指定分类及相应分类下子分类
id title parentid
1 广东省 0
2 广州 1
3 白云区 2

实现程序

 代码如下 复制代码

/*
标题:查询指定节点及其所有子节点的函数
作者:爱新觉罗.毓华(十八年风雨,守得冰山雪莲花开)
时间:2008-05-12
地点:广东深圳
*/

create table tb(id varchar(3) , pid varchar(3) , name varchar(10))
insert into tb values('001' , null  , '广东省')
insert into tb values('002' , '001' , '广州市')
insert into tb values('003' , '001' , '深圳市')
insert into tb values('004' , '002' , '天河区')
insert into tb values('005' , '003' , '罗湖区')
insert into tb values('006' , '003' , '福田区')
insert into tb values('007' , '003' , '宝安区')
insert into tb values('008' , '007' , '西乡镇')
insert into tb values('009' , '007' , '龙华镇')
insert into tb values('010' , '007' , '松岗镇')
go

--查询指定节点及其所有子节点的函数
create function f_cid(@ID varchar(3)) returns @t_level table(id varchar(3) , level int)
as
begin
  declare @level int
  set @level = 1
  insert into @t_level select @id , @level
  while @@ROWCOUNT > 0
  begin
    set @level = @level + 1
    insert into @t_level select a.id , @level
    from tb a , @t_Level b
    where a.pid = b.id and b.level = @level - 1
  end
  return
end
go

--调用函数查询001(广东省)及其所有子节点
select a.* from tb a , f_cid('001') b where a.id = b.id order by a.id
/*
id   pid  name      
---- ---- ----------
001  NULL 广东省
002  001  广州市
003  001  深圳市
004  002  天河区
005  003  罗湖区
006  003  福田区
007  003  宝安区
008  007  西乡镇
009  007  龙华镇
010  007  松岗镇

(所影响的行数为 10 行)
*/

--调用函数查询002(广州市)及其所有子节点
select a.* from tb a , f_cid('002') b where a.id = b.id order by a.id
/*
id   pid  name      
---- ---- ----------
002  001  广州市
004  002  天河区

(所影响的行数为 2 行)
*/

--调用函数查询003(深圳市)及其所有子节点
select a.* from tb a , f_cid('003') b where a.id = b.id order by a.id
/*
id   pid  name      
---- ---- ----------
003  001  深圳市
005  003  罗湖区
006  003  福田区
007  003  宝安区
008  007  西乡镇
009  007  龙华镇
010  007  松岗镇

(所影响的行数为 7 行)
*/

drop table tb
drop function f_cid

 

实例2

 

 代码如下 复制代码

t1
id     parentid
m    a
n    a
e    m
f    m
x    f
y    f
z    b

t2
row    id      amount
1    a    13.00
2    b    20.00
3    e    20.00
4    f    20.00
5    x    20.00
6    y    20.00
7    z    20.00
8    e    12.00
9    x    11.00
10    f    13.00

如何得出如下结果:

row     id      amount
7    x    20.00
11    x    11.00
    x小计    31.00
8    y    20.00
    y小计    20.00
6    f    20.00
12    f    13.00
    f小计    84.00
5    e    20.00
10    e    12.00
    e小计    32.00
3    m    14.00
    m小计    130.00
4    n    13.00
    n小计    13.00
1    a    13.00
    a小计    156.00
9    z    20.00
    z小计    20.00
2    b    20.00
    b小计    40.00
    总计    196.00

实现程序

-- 示例数据
 CREATE TABLE t1(
  id char(1),
  parentid char(1)
 );
 INSERT t1
 SELECT 'm', 'a' UNION ALL
 SELECT 'n', 'a' UNION ALL
 SELECT 'e', 'm' UNION ALL
 SELECT 'f', 'm' UNION ALL
 SELECT 'x', 'f' UNION ALL
 SELECT 'y', 'f' UNION ALL
 SELECT 'z', 'b';
 
 CREATE TABLE t2(
  row int,
  id char(1),
  amount decimal(10, 2)
 );
 INSERT t2
 SELECT '1', 'a', '13.00' UNION ALL
 SELECT '2', 'b', '20.00' UNION ALL
 SELECT '3', 'e', '20.00' UNION ALL
 SELECT '4', 'f', '20.00' UNION ALL
 SELECT '5', 'x', '20.00' UNION ALL
 SELECT '6', 'y', '20.00' UNION ALL
 SELECT '7', 'z', '20.00' UNION ALL
 SELECT '8', 'e', '12.00' UNION ALL
 SELECT '9', 'x', '11.00' UNION ALL
 SELECT '10', 'f', '13.00';
 GO
 
 -- 统计
 -- 逐级汇总
 declare @l int
 set @l=1
 
 select 
  A.[id],
  [pid] = A.parentid,
  [sumnum] = SUM(B.amount),
     level=case 
         when exists(select * from t1 where parentid=a.[id])
         then @l-1 else @l end
 into [#]
 from t1 A
  LEFT JOIN t2 B
   ON A.id = B.id
 GROUP BY A.id, A.parentid;
 
 if @@rowsqlserver/42852.htm target=_blank >count>0
     create index IDX_#_id_pid on [#]([id],[pid])
 else
     set @l=999
 
 while @@rowcount>0 or @l=1
 begin
     set @l=@l+1
     update a set level=@l,[sumnum]=isnull(a.[sumnum],0)+isnull(b.[sumnum],0)
     from [#] a,(
         select aa.pid,[sumnum]=sum(aa.[sumnum])
         from [#] aa,(
             select distinct [pid] from [#]
             where level=@l-1
         )bb where aa.[pid]=bb.[pid]
             AND NOT EXISTS(
                 SELECT * FROM [#] WHERE [PID]=aa.[PID] AND [Level]=0)
         GROUP BY aa.[PID]
         having sum(case when aa.level=0 then 1 else 0 end)=0
     )b where a.[id]=b.[pid]
 end
 
 -- 最终结果
 SELECT
  row = CASE
    WHEN GROUPING(A.row) = 0 THEN RTRIM(A.row)
    ELSE N''
   END,
  id = CASE
    WHEN GROUPING(A.row) = 0 THEN A.id
    WHEN GROUPING(A.id) = 0 THEN A.id + '小计'
    ELSE N'总计'
   END,
  amount = CASE
     WHEN GROUPING(A.row) = 0 THEN SUM(A.amount)
     WHEN GROUPING(A.id) = 0 THEN ISNULL((SELECT SUM(B.sumnum) FROM # B WHERE A.id = B.id), SUM(A.amount))
     ELSE SUM(A.amount)
    END
 FROM t2 A
 GROUP BY A.id, A.row WITH ROLLUP;
 drop table [#]
 GO
 
 DROP TABLE t1, t2;
 
 /*-- 结果
 row          id                                     amount
 ------------ ----- ---------------------------------------
 1            a                                       13.00
              a小计                                     13.00
 2            b                                       20.00
              b小计                                     20.00
 3            e                                       20.00
 8            e                                       12.00
              e小计                                     32.00
 4            f                                       20.00
 10           f                                       13.00
              f小计                                     84.00
 5            x                                       20.00
 9            x                                       11.00
              x小计                                     31.00
 6            y                                       20.00
              y小计                                     20.00
 7            z                                       20.00
              z小计                                     20.00
              总计                                     169.00
 
 (18 行受影响)
 --*/ 

性能分析:
对于一个3500条地区记录的数据表,其中有省,市,县3级
查询用时要1秒,视觉上感觉有点点慢,但不影响
数据量不大的分类,使用绝对无压力

时间: 2024-12-30 22:20:38

sql多级分类汇总实现介绍的相关文章

跪求大神给一个sql分类汇总语句

问题描述 跪求大神给一个sql分类汇总语句 10C 现有两张表:Dept:ID DName ParentDept1 总经办 02 行政部 13 企划部 1Leave:ID UserName Udept Uposition Lstart Lend Lstatus Lstype 1 张三 2 科员 2015-06-09 2015-06-10 2 12 李四 3 职员 2015-06-22 2015-06-25 3 23 王五 2 职员 2015-05-19 2015-05-22 3 2要求先按照Ud

sql select-求助sql邻近汇总问题,不是简单的分类汇总

问题描述 求助sql邻近汇总问题,不是简单的分类汇总 举例如下 已知表: table1 项目 买卖 数量 价格A 买 1 2A 买 1 4A 卖 1 2B 买 1 1A 买 1 2A 买 1 8 要求sql查询后希望达到的效果是(只对邻近的项目.买卖相同的数量汇总,价格价格取加权平均的价格)如下: 项目 买卖 数量 均价 A 买 2 3 A 卖 1 2B 买 1 1A 买 2 5 求高手给给出sql select 的示范代码. 谢谢!!?

ERP基础档案管理模块中实现多级分类档案ID号自动编码技术(V1.0)

erp|编码     ERP基础档案管理模块中实现多级分类档案ID号自动编码技术(V1.0)       本存储过程实现了多级分类档案ID号自动编码技术,本版本(V1.0)现在只实现每级3位的编码, 本版本的特点是: n          可以根据不同的数据库表产生不同的编码,达到通用化 n          调用时通过指定iIsSubNode要产生的节点编码是否是子结点还是兄弟节点来生成对应编码 进行调用本存储过程时需要注意的是需要传递节点的层次(或是叫节点的深度) 另外下一个版本(V2.0)

ERP基础档案管理模块中实现多级分类档案级联删除技术

erp ERP基础档案管理模块中实现多级分类档案级联删除技术   本存储过程实现了多级分类档案级联删除技术 本存储过程的特点是: n          可以在不同的数据库表上应用此存储过程,以达到通用化 n          同时用户也可以根据不同的表结构,选择相应版本的的存储过程,在这里共有三个版本可供用户选择,分别对应表结构中有无节点的深度字段等情况 进行调用本存储过程时只需要传递节点号及表名即可,但是用户选择相应版本进行应用时,需要针对实际情况作出选择 版本一 CREATE procedu

WPS表格分类汇总在生活中的妙用

  在表格的使用过程中,我们不仅仅对工作或学习上的数据输入,平常对一些结算的数据汇总,也是能帮到一定忙.下面小编就给大家介绍下WPS表格中分类汇总的使用方法,小伙伴们一定大吃一惊的. 1 从实例开始 订餐记录 我每日服务于所在的集体,朋友们中午的订餐任务由我来承担.为了付款简单,餐费采取周结的方式,每周五我统计出来向大家收取,一个记录每天订餐信息的表格逐渐呈现在我面前. 应该说,这个表格还是很清楚的,至少需要反映的基础信息都在上面了. 之所用电子表格来记录它,就是因为我可以在数据的最下方直接看到

SQL语句(T-SQL汇总) 用T-SQL画出这些图形_MsSql

我个人感觉数据库这方面对于程序员来说很重要,无论是对于JAVA程序员还是DOTNET程序员以及其他编程人员来说都是必须掌握的.为了帮助大家更好的来回顾T-SQL,本人利用空闲的时间整理的一下T-SQL的语句和语法.希望对大家有用! 好的!我们先来看几个图像: 棱形三角形正方形圆形矩形梯形 上面这些图形都是用T-SQL实现的,文章的最后我们一起来用T-SQL画出这些图形. 首先,我们开始回顾一下T-SQL的基本语法: 函数 abs(x):求绝对值: 例: select abs(-3) 值为:3 s

sql-实现分类汇总功能,求大神指导,跪求

问题描述 实现分类汇总功能,求大神指导,跪求 目前我实现的功能是点击"问答表"中标题的超链接,就会在action中执行一个把这条记录保存到另一张表"访问记录"里.现在我想在"问答表"加一个字段"fangwencishu"然后在"问答表"页面显示出来?求大神赐教,如何查处这个页面呢?(没点击过得标题访问次数显示0)通过sql能直接查出来吗?还是别的方法?求告知. 解决方案 用querystring传参数,页面

smarty实现多级分类的方法_php技巧

本文实例讲述了smarty实现多级分类的方法.分享给大家供大家参考.具体分析如下: 这里简单的介绍一下利用php smarty 多级分类读出与循环方法,单循环很简单,但是多级就要复杂一点,下面我们来看看,感兴趣的朋友可以看来一下: 复制代码 代码如下: <?php $result=mysql_query("SELECT id,description,parent_id,name,sort_order FROM article_categoey WHERE parent_id=0 order

分类汇总问题、求大神帮忙解决。跪求

问题描述 分类汇总问题.求大神帮忙解决.跪求 下边是我实现第一个图的代码,现在我想实现第二张图查询出来的模式,第二张图的错误次数是该用户的记录次数(一个名词出现的次数).这个同事告诉我是分类汇总问题. 求大神指导下怎么弄,跪求~ public String getList() throws Exception { chengJiJiLuList = dao.getList(TrainingOrCompetitionID,startTime,endTime); ArrayList chengJiJ