トップページに戻る
次のSQLパズルへ
前のSQLパズルへ
9-2 和集合を求めて、スカラー問い合わせ
SQLパズル
Itemsテーブル
Item_no description
------- -----------
10 Item10
20 Item20
30 Item30
40 Item40
50 Item50
Actualsテーブル
Item_no act check_no
------- --- --------
10 300 1111
20 325 2222
20 100 3333
30 525 1111
Estimatesテーブル
Item_no est
------- ---
10 300
10 50
20 325
20 110
40 25
上の3テーブルから以下の出力を行う。
出力結果
Item_no description tot_act tot_est check_no
------- ----------- ------- ------- --------
10 Item10 300 350 1111
20 Item20 425 435 Mixed
30 Item30 525 NULL 1111
40 Item40 NULL 25 NULL
SQLパズル(日本語版)のパズル37 [予算報告書] を参考にさせていただきました
SQLパズル 第2版のパズル41 [予算] を参考にさせていただきました
データ作成スクリプト
create table Items(
Item_no number(2),
description char(7));
insert into Items values(10,'Item10');
insert into Items values(20,'Item20');
insert into Items values(30,'Item30');
insert into Items values(40,'Item40');
insert into Items values(50,'Item50');
create table Actuals(
Item_no number(2),
act number(3),
check_no char(4));
insert into Actuals values(10,300,'1111');
insert into Actuals values(20,325,'2222');
insert into Actuals values(20,100,'3333');
insert into Actuals values(30,525,'1111');
create table Estimates(
Item_no number(2),
est number(3));
insert into Estimates values(10,300);
insert into Estimates values(10, 50);
insert into Estimates values(20,325);
insert into Estimates values(20,110);
insert into Estimates values(40, 25);
commit;
SQL
--■■■インラインビューと外部結合を使う方法■■■
select a.Item_no,a.description,b.tot_act,c.tot_est,b.check_no
from Items a
Left Join (select Item_no,sum(act) as tot_act,
case when count(check_no) >=2 then 'Mixed'
when count(check_no) = 1 then max(check_no) end as check_no
from Actuals
group by Item_no) b
on b.Item_no = a.Item_no
Left Join (select Item_no,sum(est) as tot_est
from Estimates
group by Item_no) c
on c.Item_no = a.Item_no
where nvl(b.Item_no,c.Item_no) is not null
order by a.Item_no;
--■■■unionとサブクエリを使う方法■■■
select a.Item_no,
(select b.description from Items b where b.Item_no=a.Item_no) as description,
(select sum(b.act) from Actuals b where b.Item_no=a.Item_no) as tot_act,
(select sum(b.est) from Estimates b where b.Item_no=a.Item_no) as tot_est,
case when (select count(b.Item_no) from Actuals b
where b.Item_no=a.Item_no
and RowNum <= 2 ) = 2 then 'Mixed'
else (select b.check_no from Actuals b where b.Item_no=a.Item_no) end as check_no
from (select Item_no from Actuals
union select Item_no from Estimates) a
order by a.Item_no;
--■■■完全外部結合と分析関数を使う方法■■■
with ActualsView as(
select distinct Item_no,
sum(act) over(partition by Item_no) as tot_act,
case when count(act) over(partition by Item_no) >= 2
then 'Mixed' else check_no end as check_no
from Actuals),
EstimatesView as(
select distinct Item_no,
sum(est) over(partition by Item_no) as tot_est
from Estimates)
select coalesce(a.Item_no,b.Item_no) as Item_no,
c.description,a.tot_act,b.tot_est,a.check_no
from ActualsView a full join EstimatesView b
on a.Item_no = b.Item_no
Left Join Items c
on coalesce(a.Item_no,b.Item_no) = c.Item_no
order by Item_no;
--■■■Outer Unionもどきを使う方法■■■
select a.Item_no,b.description,
sum(a.act) as tot_act,
sum(a.est) as tot_est,
case when count(a.check_no) > 1 then 'Mixed'
when count(a.check_no) = 1 then max(a.check_no) end as check_no
from (select Item_no,act,check_no,to_number(null) as est from Actuals
union all
select Item_no,to_number(null),to_char(null),est from Estimates) a,
Items b
where a.Item_no = b.Item_no
group by a.Item_no,b.description
order by a.Item_no,b.description;
解説
unionで和集合を求めて、Item_noの一覧を作成し、
select句でスカラー問い合わせを使う方法や、
完全外部結合と分析関数を使う方法などがあります。