转:http://www.111cn.net/database/mssqlserver/43368.htm 
本文章介绍了关于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('' , null , '广东省')
insert into tb values('' , '' , '广州市')
insert into tb values('' , '' , '深圳市')
insert into tb values('' , '' , '天河区')
insert into tb values('' , '' , '罗湖区')
insert into tb values('' , '' , '福田区')
insert into tb values('' , '' , '宝安区')
insert into tb values('' , '' , '西乡镇')
insert into tb values('' , '' , '龙华镇')
insert into tb values('' , '' , '松岗镇')
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('') 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('') 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('') 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 '', 'a', '13.00' UNION ALL
SELECT '', 'b', '20.00' UNION ALL
SELECT '', 'e', '20.00' UNION ALL
SELECT '', 'f', '20.00' UNION ALL
SELECT '', 'x', '20.00' UNION ALL
SELECT '', 'y', '20.00' UNION ALL
SELECT '', 'z', '20.00' UNION ALL
SELECT '', 'e', '12.00' UNION ALL
SELECT '', 'x', '11.00' UNION ALL
SELECT '', '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 行受影响)
--*/

MS SQL 分类汇总参数 grouping(**)=1 rollup cubt的更多相关文章

  1. (2.4)DDL增强功能-数据汇总grouping、rollup、cube

    参考:https://www.cnblogs.com/nikyxxx/archive/2012/11/27/2791001.html 1.rollup (1)rollup在group by 子句中使用 ...

  2. SQL之按两个字段分类汇总

    目的: 同时按"游戏代号"和"礼包名"分类汇总,然后获取下拉框的数据.  如下图所示: SQL查询 select game,giftname from qyg_ ...

  3. SQL GROUP BY GROUPING SETS,ROLLUP,CUBE(需求举例)

    实现按照不同级别分组统计 关于GROUP BY 中的GROUPING SETS,ROLLUP,CUBE 从需求的角度理解会更加容易些. 需求举例: 假如一所学校只有两个系, 每个系有两个专业, 每个专 ...

  4. SQL Server case when 实现分类汇总

    case when 实现分类汇总

  5. MariaDB——SQL语句分类汇总

    常用SQL语句汇总 SQL语句在所有的关系型数据库中都是通用的,算起来sql语句也是一门语言,只不过这门语言的主要操作对象是关系型的数据库,其中最常用的还是查询相关的语句. sql语句主要分为: DQ ...

  6. MS SQL优化

    数据库优化实践[MS SQL优化开篇]   数据库定义: 数据库是依照某种数据模型组织起来并存在二级存储器中的数据集合,此集合具有尽可能不重复,以最优方式为特定组织提供多种应用服务,其数据结构独立于应 ...

  7. MS SQL 日志记录管理

    MS SQL的日志信息/日志记录,可能对你来说,既熟悉又陌生,熟悉是因为你可能一直都在使用,查看.关注一些日志信息/记录,例如,作业历史记录:陌生是因为你可能从不关注日志信息/记录的管理,这里我一直用 ...

  8. MS SQL 字符拆分存处理

    MS SQL Server没有split()函数,但是我们可以写一个Table-valued Functions定义函数[dbo].[udf_SplitStringToTable] : CREATE ...

  9. 在易语言中调用MS SQL SERVER数据库存储过程方法总结

    Microsoft SQL SERVER 数据库存储过程,根据其输入输出数据,笼统的可以分为以下几种情况或其组合:无输入,有一个或多个输入参数,无输出,直接返回(return)一个值,通过output ...

随机推荐

  1. linux-shell父子进程

          用户登录到Linux系统后,系统将启动一个用户shell.在这个shell中,可以使用shell命令声明变量,也可以创建并运行 shell脚本程序.运行shell脚本程序时,系统将创建一个 ...

  2. Java 根据年月日精确计算年龄

    import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; /** * Created b ...

  3. sqlite db-journal文件产生原因及说明

    今天在Android中将sqlite的数据库文件生成在SD卡上的过程中,发现生成的.db文件的旁边 生成了一个大小为0的与数据库文件同名的.db-journal文件,不明白此文件的用途,于是 goog ...

  4. etcd集群日常维护

    配置文件和启动参数说明 命令行 | 配置文件 | 说明 data-dir | ETCD_DATA_DIR | 指定节点的数据存储目录,包括节点ID,集群ID,集群初始化配置,Snapshot文件,若未 ...

  5. django模板解析 循环列表中 切片和求长度

    {% for subrow in subdic.content|slice:":5" %} {% endfor %} {% if "{{subdic.content|le ...

  6. C++之类成员所占内存大小问题总结

    1.空类所占字节数为1,可见代码如下 #include <iostream> using namespace std; class Parent { }; class Child:publ ...

  7. GPU hang

    最近做新项目 初期一直遇到个gpu hang的问题 就是command 提交过去gpu 就一直在那里 直到time out 也没什么别的错误提示 gpu debugger还抓不了 解决方案是 缩小之后 ...

  8. MySQL的id生成策略

    1 自增 CREATE TABLE `test` ( `id` ) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAUL ...

  9. zabbix自定义监控项一

    1.在agent端配置 1.1 添加自定义监控项 zabbix中监控项叫做item,监控项的取值方法叫做key item: Items是从agnet主机里面获取的所有数据.通常情况下我叫itme为监控 ...

  10. 将 xml 文件 转为 DataTable

    private static DataTable CreateDataTable(string table) { DataSet dataSet = new DataSet(); string dat ...