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

10-219 元集合の重複を残す差集合演算

SQLパズル

TableX  TableY  TableZ
Val     Val     Val
---     ---     ---
  1       1       2
  2       2       3
  3       5       5
  4       6

TableXのValと、TableYのValの和集合(重複を残す和集合)
と
TableZとの差集合
を求める。

ただし、差集合演算において、元集合の重複は残す。

出力結果
Val
---
  1
  1
  4
  6


データ作成スクリプト

create table TableX(Val primary key) as
select 1 from dual union
select 2 from dual union
select 3 from dual union
select 4 from dual;

create table TableY(Val primary key) as
select 1 from dual union
select 2 from dual union
select 5 from dual union
select 6 from dual;

create table TableZ(Val primary key) as
select 2 from dual union
select 3 from dual union
select 5 from dual;


SQL

--■■■最初のselectを括弧でくくらない方法■■■
select * from TableX
 minus
select * from TableZ
union all
(select * from TableY
  minus
 select * from TableZ)
order by 1;

--■■■最初のselectを括弧でくくる方法■■■
(select * from TableX
  minus
 select * from TableZ)
union all
(select * from TableY
  minus
 select * from TableZ)
order by 1;


解説

Boolean algebra
のSet Versionの2番 (集合の分配法則)
A∩(B∪C) = (A∩B)∪(A∩C)
を使って導いた等式の、
          _       _        _
(X∪Y) ∩ Z = (X∩Z) ∪ (Y∩Z)
を使ってます。(ベン図を脳内でイメージすると分かりやすいでしょう)

集合の分配法則は、
ブール代数の分配法則とセットで覚えるといいでしょう。
      _      _       _
(X+Y)*Z = (X*Z) + (Y*Z)

集合論――数学の「集合論」に,RDBの正体を見る

なお、
A∩(B∪C) = (A∩B)∪(A∩C)  に、双対の原理を適用すると
A∪(B∩C) = (A∪B)∩(A∪C)  を得ることができます。

■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

not existsを使うのが良さそうですが、
使い捨てのSQLで、列数が多くて、
select *
を使いたいときに、使い道があるかもしれません。

■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

最初に括弧を使う形は、文法上正式に許可されているか不明です。
UNION [ALL]、INTERSECTおよびMINUS演算子

(select 1 from dual
  union
 select 2 from dual)
union all
(select 1 from dual
  union
 select 2 from dual);