トップページに戻る    次のSQLパズルへ    前のSQLパズルへ

9-56 集合が等しい組み合わせを求める

SQLパズル

SupPartsテーブル
sup  part
---  ------
AAA  ボルト
AAA  ナット
AAA  パイプ
BBB  ボルト
BBB  パイプ
CCC  ボルト
CCC  ナット
CCC  パイプ
DDD  ボルト
DDD  パイプ
EEE  ヒューズ
EEE  ナット
EEE  パイプ
FFF  ヒューズ

supごとの、partの集合の組み合わせで、
集合が等しい組み合わせを、
以下の形式で出力する。

SupPartsテーブルに重複行は存在しないものとする。

出力結果
S1   S2
---  ---
AAA  CCC
BBB  DDD
9-27 集合の包含関係を調べるのアレンジです


データ作成スクリプト

create table SupParts(
sup  char(3),
part varchar2(8),
primary key(sup,part));

insert into SupParts
select 'AAA','ボルト' from dual
union select 'AAA','ナット'   from dual
union select 'AAA','パイプ'   from dual
union select 'BBB','ボルト'   from dual
union select 'BBB','パイプ'   from dual
union select 'CCC','ボルト'   from dual
union select 'CCC','ナット'   from dual
union select 'CCC','パイプ'   from dual
union select 'DDD','ボルト'   from dual
union select 'DDD','パイプ'   from dual
union select 'EEE','ヒューズ' from dual
union select 'EEE','ナット'   from dual
union select 'EEE','パイプ'   from dual
union select 'FFF','ヒューズ' from dual;
commit;


SQL

--■■■分析関数を使う方法■■■
select distinct s1,s2
from (select a.sup as s1,b.sup as s2,
      count(distinct a.part) over(partition by a.sup,b.sup) as SupCount1,
      count(distinct b.part) over(partition by a.sup,b.sup) as SupCount2,
      count(decode(a.part,b.part,1))
      over(partition by a.sup,b.sup) as ExistSum
        from SupParts a,SupParts b
       where a.sup < b.sup)
where ExistSum = all(SupCount1,SupCount2);

--■■■分析関数を使わない方法■■■
select a.sup as s1,b.sup as s2
  from SupParts a,SupParts b
 where a.sup < b.sup
group by a.sup,b.sup
having count(decode(a.part,b.part,1))
     = all(count(distinct a.part),count(distinct b.part));

--■■■件数を内部結合の条件にする方法■■■
with work as(
select sup,part,count(*) over(partition by sup) as cnt
  from SupParts)
select a.sup as s1,b.sup as s2
  from work a,work b
 where a.sup < b.sup
   and a.cnt = b.cnt
   and a.part = b.part
group by a.sup,b.sup,a.cnt
having count(*) = a.cnt
order by a.sup,b.sup;


解説

集合の一致
ふたつの集合AとBに対して、AとBとが等しいとは、
A⊂B と B⊂A が両方とも成り立つときをいう。
またこのときA=Bと書く。

だそうですが

(集合Aに重複した要素が存在しない、かつ、集合Bに重複した要素が存在しない)
かつ
(A⊂B、または、B⊃Aが成立する)
かつ
集合Aと集合Bの要素数が等しい

と、A=Bも同値です。

という論理を使ってます。

■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
・count(distinct a.part) = count(distinct b.part) によって、要素数が等しい
・count(decode(a.part,b.part,1) = count(distinct a.part) によって、包含関係が成立

having句で、上記2つの論理積が真となる組み合わせを抽出しているのです。

■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
集合が等しいことの必要十分条件の証明
数学的に厳密に正しい証明かは、分かりません。

----------------------------------------------------------
集合Aと集合Bの要素数が等しい。 すなわち  n(A) = n(B)
かつ
少なくとも1つの包含関係が成立する。 すなわち  A⊂B または A⊃B
----------------------------------------------------------

集合Aと集合Bが等しいパターン1
(要素数は一致する。
片方の包含関係でいいのですが、互いに包含関係が成立)
SetA    SetB
-----   -----
Item1   Item1
Item2   Item2

集合Aと集合Bが等しいパターン2
(要素数は一致する。
片方の包含関係でいいのですが、互いに包含関係が成立)
SetA    SetB
-----   -----
空集合   空集合

集合Aと集合Bが等しくないパターン1
(要素数は一致するが、どちらの包含関係も成立せず)
SetA    SetB
-----   -----
Item1   Item1
Item2   Item3

集合Aと集合Bが等しくないパターン2
(要素数は一致するが、どちらの包含関係も成立せず)
SetA    SetB
-----   -----
Item1   Item3
Item2   Item4

集合Aと集合Bが等しくないパターン3
(片方の包含関係が成立するが、要素数が一致せず)
SetA    SetB
-----   -----
Item1   Item1
Item2   Item2
        Item3

集合Aと集合Bが等しくないパターン4
(片方の包含関係が成立するが、要素数が一致せず)
SetA    SetB
-----   ------
Item1    空集合
Item2

10-311 紐づく集合の一致を調べる

CodeZine:SQLで集合演算
CodeZine:分析関数の衝撃(完結編)

OTNのスレッド