Oracle plsql遞迴統計所有節點下的子節點&內容個數——start with connect by prior用法
有些情況下,在存有層級關係的表中,id欄位值本身會包含層級關係,例如每兩位表示一級。
要想只統計某個或某幾個層級節點下子節點+內容個數,就需要使用類似like ‘01%’的過濾條件即可。
例如select count(1) from test_category t where t.cid like '01%' or t.cid like '02%‘;
但是,如果id值本身無法表示層級關係,那麼必須使用如下方法,即使是隻統計某個或某幾個層級節點下子節點+內容個數。/**遞迴查詢
已知,節點下可以掛子節點或者內容,
葉子節點下只能掛內容,
內容下不能掛節點。
要統計每個節點下的內容個數(包括自己的內容和子節點的內容)
*/
----測試資料
--節點表
create table test_category(
cid varchar2(20),
parentid varchar2(20)
);
--內容記錄表
create table test_category2content(
cateid varchar2(20),
contid varchar2(20),
record_date varchar(8)
);
--分支1
insert into test_category values('1', '0');
insert into test_category values('11', '1');
insert into test_category values('12', '1');----葉子節點
insert into test_category values('111', '11');----葉子節點
insert into test_category values('112', '11');
insert into test_category2content values('1', 'X', '20170606');
insert into test_category2content values('1', 'X', '20170607');
insert into test_category2content values('11', 'X', '20170606');
insert into test_category2content values('11', 'X', '20170607');
insert into test_category2content values('12', 'X', '20170606');
insert into test_category2content values('12', 'X', '20170607');
insert into test_category2content values('111', 'X', '20170606');
insert into test_category2content values('111', 'X', '20170607');
insert into test_category2content values('111', 'X', '20170608');
---分支2
--insert into test_category2content values('2', 'X', '20170606');
--insert into test_category2content values('21', 'X', '20170607');
--insert into test_category values('2', '0');
--insert into test_category values('21', '2');
--insert into test_category values('211', '21');----設為葉子節點
commit;
---結果:
--1:9
--11:5
--12:2
--111:3
--112:0
----正確的做法
select x.cid
, (
select sum(nvl(t2.amount, 0))--t1.cid, nvl(t2.amount, 0) as amount
from test_category t1 left join
(select cateid, count(1) as amount from test_category2content group by cateid) t2
on t1.cid = t2.cateid
start with t1.cid = x.cid
connect by prior t1.cid = t1.parentid
) as cc
from test_category x
;
---如果要統計給定日期(例如20170606)的各個節點下的子節點個數,就需要加上where語句
(下面這段語句是根據我專案中使用到的sql語句進行改寫的,沒有調測過)
select x.cid
, '20170606' as datet
, (
select sum(nvl(t2.amount, 0))--t1.cid, nvl(t2.amount, 0) as amount
from test_category t1 left join
(select cateid
, record_date as datet
, count(1) as amount from test_category2content group by cateid, record_date) t2
on t1.cid = t2.cateid
where t2.datet = '20170606'-----added
start with t1.cid = x.cid
connect by prior t1.cid = t1.parentid
) as cc
from test_category x
;
----//====稍微研究下connect by的作用
---從parentid到cid開始遞迴,並以parentid為主展示這條記錄
select t1.parentid, t1.cid, level
from test_category t1
start with t1.parentid = 1
connect by prior t1.parentid = t1.cid
;
---從parentid到cid開始遞迴,並以parentid為主展示這條記錄
select t1.parentid, t1.cid, level
from test_category t1
start with t1.cid = 1
connect by prior t1.parentid = t1.cid
;
---從parentid到cid開始遞迴,並以cid為主展示這條記錄
select t1.cid, t1.parentid, level
from test_category t1
start with t1.parentid = 1
connect by t1.parentid = prior t1.cid
;
---從parentid到cid開始遞迴,並以cid為主展示這條記錄
select t1.cid, t1.parentid, level
from test_category t1
start with t1.cid = 1
connect by t1.parentid = prior t1.cid
;