トップページに戻る
次のSQLパズルへ
前のSQLパズルへ
10-337 子ノードでの総和を計算
SQLパズル
treeNodeT
ID oyaID quantity cost
-- ----- -------- ----
AA null 2 null
BB AA 3 null
CC BB 4 null
DD CC 2 10
EE CC 1 5
costがnullであれば、
cost = それぞれの子ノードのquantity*costの、合計
としてレベルの高いノードから順にcostを求めていく。
また、quantity*cost の値を"Total Unit Cost"として求める。
出力結果
ID oyaID quantity cost Total Unit Cost
-- ----- -------- ---- ---------------
AA null 2 300 600
BB AA 3 100 300
CC BB 4 25 100
EE CC 1 5 5
DD CC 2 10 20
データ作成スクリプト
create table treeNodeT(ID,oyaID,quantity,cost) as
select 'AA',null,2,null from dual union all
select 'BB','AA',3,null from dual union all
select 'CC','BB',4,null from dual union all
select 'DD','CC',2, 10 from dual union all
select 'EE','CC',1, 5 from dual;
SQL
col oyaID for a10
--■■■model句を使う方法(10g以降)■■■
select ID,oyaID,quantity,cost,
quantity*cost as "Total Unit Cost"
from treeNodeT
start with oyaID is null
connect by prior ID = oyaID
model
dimension by(ID,oyaID)
measures(quantity,cost,Row_Number() over(order by Level desc) as rn)
rules(cost[any,any] order by rn=
case when cost[cv(),cv()] is null
then sum(cost*quantity)[any,cv(ID)]
else cost[cv(),cv()] end)
order by rn desc;
--■■■表関数を使う方法■■■
create or replace package Pack10_337 Is
type PrintRType Is record(
ID treeNodeT.ID%type,
oyaID treeNodeT.ID%type,
quantity number(1),
cost number(3),
SortKey number(1));
type PrintRTypeSet Is table of PrintRType;
end;
/
create or replace function PrintR10337 return Pack10_337.PrintRTypeSet PipeLined IS
outR Pack10_337.PrintRType;
cursor cur is
select ID,oyaID,quantity,cost
from treeNodeT
start with oyaID is null
connect by prior ID = oyaID
order by Level desc;
type saveDataDef is table of cur%rowType index by binary_integer;
saveData saveDataDef;
wkCost treeNodeT.cost%type;
begin
open cur;
fetch cur bulk collect into saveData;
close cur;
for I in 1..saveData.Last Loop
if saveData(I).cost is null then
wkCost := 0;
for J in reverse saveData.First..I Loop
if saveData(I).ID = saveData(J).oyaID then
wkCost := wkCost + saveData(J).cost*saveData(J).quantity;
end if;
end Loop;
saveData(I).cost := wkCost;
end if;
end Loop;
for I in 1..saveData.Last Loop
outR.ID := saveData(I).ID;
outR.oyaID := saveData(I).oyaID;
outR.quantity := saveData(I).quantity;
outR.cost := saveData(I).cost;
outR.SortKey := I;
pipe row(outR);
end Loop;
end;
/
sho err
col oyaID for a10
select ID,oyaID,quantity,cost,
quantity*cost as "Total Unit Cost"
from table(PrintR10337) order by SortKey desc;
解説
model句のdimension指定で子にアクセスしてます。
親子関係においてレベルが1違うだけならmodel句のdimension指定が便利なこともあります。