トップページに戻る
次のSQLパズルへ
前のSQLパズルへ
10-339 等しい集合を持つグループを、外部結合で見つける
SQLパズル
ordテーブル mapテーブル
ordID prodID pkgID prodID
----- ------ ----- ------
101 1 10 1
101 2 10 2
102 1 20 1
102 3 20 3
103 1 30 2
103 2 30 3
103 3 40 1
104 1 40 2
40 3
ordテーブルのordIDごとに
mapテーブルのpkgIDごとで、prodIDと数と値が一致する、pkgIDを表示する。
該当pkgIDがなければnullとする。
出力結果
ordID pkgID
----- -----
101 1
102 2
103 4
104 null
データ作成スクリプト
create table ord(ordID,prodID) as
select 101,1 from dual union all
select 101,2 from dual union all
select 102,1 from dual union all
select 102,3 from dual union all
select 103,1 from dual union all
select 103,2 from dual union all
select 103,3 from dual union all
select 104,1 from dual;
create table map(pkgID,prodID) as
select 10,1 from dual union all
select 10,2 from dual union all
select 20,1 from dual union all
select 20,3 from dual union all
select 30,2 from dual union all
select 30,3 from dual union all
select 40,1 from dual union all
select 40,2 from dual union all
select 40,3 from dual;
SQL
--■■■分析関数のcount関数を使う方法■■■
select ordID,max(pkgID) as pkgID
from (select a.ordID,
decode(a.cnt,count(*),b.pkgID) as pkgID
from (select ordID,prodID,
count(*) over(partition by ordID) as cnt
from ord) a
Left Join
(select pkgID,prodID,
count(*) over(partition by pkgID) as cnt
from map) b
on a.cnt=b.cnt
and a.prodID=b.prodID
group by a.ordID,a.cnt,b.pkgID)
group by ordID
order by ordID;
--■■■ListAgg関数を使う方法(11gR2以降)■■■
select a.ordID,b.pkgID
from (select ordID,
ListAgg(to_char(prodID),',') within group (order by prodID) as ListProdID
from ord
group by ordID) a,
(select pkgID,
ListAgg(to_char(prodID),',') within group (order by prodID) as ListProdID
from map
group by pkgID) b
where a.ListProdID=b.ListProdID(+)
order by a.ordID;
解説
(集合Aに重複した要素が存在しない、かつ、集合Bに重複した要素が存在しない)
かつ
(A⊂B、または、B⊃Aが成立する)
かつ
集合Aと集合Bの要素数が等しい
かを調べてます。
9-27 集合の包含関係を調べる
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
ListAgg関数を使うのもいいと思います。