写一个有父子关系的累加统计的sql

这样的需求是很常见的。 

经常我们需要对一个有父子层次结构关系的表进行累加统计的显示, 

比如 
部门赢利的统计, 父部门就是所有部门的赢利总和,起二级部门又是下面的子部门的赢利的总和,依次下去,这样的sql如何来写叻。 

实现的逻辑方式, 根据父子关系,确定好包含关系,用path来表示结构,然后自关联。用instr来做管理, 
比如

引用:
部门 
部门1 
部门102 
部门10201


如果这里已经是表示出了path的关系最好,这里已经表示出来了, 
如果不能表示,可以用sys_connect_by_path来表示出来 

引用:
name path 
部门 
部门1 部门,部门1 
部门102 部门,部门1,部门102 
部门10201 部门,部门1,部门102,部门10201



如果有这样的关系用instr做连接自关联就可以了 
比如a left join b instr(b.path||',', a.name||',', 1, 1) = 1这样就可以做累加结果集了 


用一个实例来做做 
业务表:sr_zc 
基础表:sr、zc

引用:
create table SR_ZC 

ZC CHAR(2), 
BS_CODE VARCHAR2(42), 
IN_BS_CODE VARCHAR2(42), 
MONEY NUMBER 
); 

create table SR 

CHR_CODE VARCHAR2(42) 
); 

create table ZC 

CHR_CODE VARCHAR2(42) 
);



部分测试数据 完整测试数据可以在附件里下载 

引用:
insert into sr (CHR_CODE) values ('101'); 
insert into sr (CHR_CODE) values ('10101'); 
insert into sr (CHR_CODE) values ('1010101'); 
insert into sr (CHR_CODE) values ('101010101'); 

insert into zc (CHR_CODE) values ('201'); 
insert into zc (CHR_CODE) values ('20101'); 
insert into zc (CHR_CODE) values ('2010101'); 
insert into zc (CHR_CODE) values ('2010102'); 
insert into zc (CHR_CODE) values ('2010103'); 
insert into zc (CHR_CODE) values ('2010104'); 
insert into zc (CHR_CODE) values ('2010105'); 
insert into zc (CHR_CODE) values ('2010106'); 
insert into zc (CHR_CODE) values ('2010107'); 

insert into sr_zc (ZC, BS_CODE, IN_BS_CODE, MONEY) values ('zc', '2010101', '', 387101.62); 
insert into sr_zc (ZC, BS_CODE, IN_BS_CODE, MONEY) values ('zc', '2010101', '', 269192.35); 
insert into sr_zc (ZC, BS_CODE, IN_BS_CODE, MONEY) values ('zc', '2010101', '', 13300); 
insert into sr_zc (ZC, BS_CODE, IN_BS_CODE, MONEY) values ('zc', '2010101', '', 57848); 
insert into sr_zc (ZC, BS_CODE, IN_BS_CODE, MONEY) values ('zc', '2010102', '', 262374); 

insert into sr_zc (ZC, BS_CODE, IN_BS_CODE, MONEY) values ('sr', '', '101044002', 953587.47); 
insert into sr_zc (ZC, BS_CODE, IN_BS_CODE, MONEY) values ('sr', '', '101044003', 437688.31); 
insert into sr_zc (ZC, BS_CODE, IN_BS_CODE, MONEY) values ('sr', '', '101044099', 1937.22); 
insert into sr_zc (ZC, BS_CODE, IN_BS_CODE, MONEY) values ('sr', '', '101044102', 1124444.96); 
insert into sr_zc (ZC, BS_CODE, IN_BS_CODE, MONEY) values ('sr', '', '101044103', 35336.21); 
insert into sr_zc (ZC, BS_CODE, IN_BS_CODE, MONEY) values ('sr', '', '101044199', 657.29); 
insert into sr_zc (ZC, BS_CODE, IN_BS_CODE, MONEY) values ('sr', '', '101045001', 18943.25); 

这里两个基表都是描述的code,而且比较方便的是,父子关系也通过code表示出来了 
比如 
201 -- 1级 
20101 -- 2级 
2010101 -- 3级 
2010102 -- 3级 
201010201 -- 4级



sr_zc是数据表,数据都存在这里面了,存的时候, ZC表示和那个表关联, 如果是sr就用IN_BS_CODE关联和sr表, 如果是zc就是用BS_CODE和zc表关联 

结果要得到类似于这样的统计 

引用:
SR_CODE SR_MONEY ZC_CODE ZC_MONEY 
101 11111 201 111111 
10101 5000 20101 3000



这样的统计 

先从简单开始,先做成这样的格式在说,这里我的方法是先把SR的记录都选出来,在把ZC的记录选出来。然后用rownum做full join把结果集用列的方式union起来 

如下 

引用:
select t1.SR_CODE, t1. SR_MONEY, t2.ZC_CODE, t2.ZC_MONEY from 
(select a.IN_BS_CODE SR_CODE, a.MONEY SR_MONEY, rownum no from SR_ZC a, SR b where a.ZC='sr' and a.IN_BS_CODE =b.CHR_CODE) t1 
full join 
(select a. BS_CODE ZC_CODE, a.MONEY ZC_MONEY, rownum no from SR_ZC a, ZC b where a.ZC='zc' and a.BS_CODE =b.CHR_CODE) t2 
on t1.no=t2.no;



不过这里问题出来了,有重复记录 

接着来 

引用:
SQL> col SR_CODE format a15; 
SQL> col zc_CODE format a15; 
SQL> col SR_MONEY format 999999999.9; 
SQL> col ZC_MONEY format 999999999.9; 

select t1.SR_CODE, t1. SR_MONEY, t2.ZC_CODE, t2.ZC_MONEY 
from (select t.*, rownum no from ( 
select a.IN_BS_CODE SR_CODE, sum(a.MONEY) SR_MONEY from SR_ZC a, 
SR b where a.ZC='sr' and a.IN_BS_CODE =b.CHR_CODE group by a.IN_BS_CODE) t) t1 

full join 
(select t.*, rownum no from ( 
select a. BS_CODE ZC_CODE, sum(a.MONEY) ZC_MONEY from SR_ZC a, Z 
C b where a.ZC='zc' and a.BS_CODE =b.CHR_CODE group by a. BS_CODE) t ) t2 
7 on t1.no=t2.no;



现在已经基本上union正确了, 

不过还是没有得到最后的要求,需要按层次关系把money累加, 

用上面的方式 这里用到了两个left join是预防数据表里没有主表的记录的情况, 

如下 

引用:
select SR_CODE,SR_MONEY,ZC_CODE,ZC_MONEY 
from 
(select t.*, rownum no 
from 
(select b.chr_code SR_CODE, sum(nvl(c.money,0)) SR_MONEY from SR b left join SR_ZC a on a.IN_BS_CODE =b.CHR_CODE and a.zc='sr' left join SR_ZC c on instr(c.IN_BS_CODE, b.CHR_CODE, 1, 1)=1 and c.zc='sr' group by b.chr_code order by b.chr_code asc) t) t1 
full join 
(select t.*, rownum no 
from (select b.chr_code ZC_CODE, sum(nvl(c.money,0)) ZC_MONEY from ZC b left join SR_ZC a on a.BS_CODE =b.CHR_CODE and a.zc='zc' left join SR_ZC c on instr(c.BS_CODE, b.CHR_CODE, 1, 1)=1 and c.zc='zc' group by b.chr_code order by b.chr_code asc) t) t2 
on t1.no=t2.no 
order by SR_CODE asc, ZC_CODE asc



这里就达到开始的要求了,这里只是想记录一下这类问题的解决思路,记一下,有需要这样的sql的,就知道如何来解决了。 

附件里有完整的测试数据的脚本,运行一下,体验一下,最后出来和你想要一致的记录集的喜悦吧。

 

附件

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

inthirties

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值