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

9-49 集合とブール代数で考える

SQLパズル

AggTestテーブル
ID  Val
--  ---
 1   P
 1   P
 1   U
 1   U
 2   P
 2   P
 3   U
 3   U
 4   F
 4   F
 5   P
 5   F

IDごとに、以下の条件を2つとも満たさないIDを出力する

・ValがPのみである
・ValがPとUのレコードがともに1つ以上存在し、ValがPとUのみである

出力結果
ID
--
 3
 4
 5
9-48 集合で考えるのアレンジ問題です


データ作成スクリプト

create table AggTest as
select 1 as ID,'P' as Val from dual
union all select 1,'P' from dual
union all select 1,'U' from dual
union all select 1,'U' from dual
union all select 2,'P' from dual
union all select 2,'P' from dual
union all select 3,'U' from dual
union all select 3,'U' from dual
union all select 4,'F' from dual
union all select 4,'F' from dual
union all select 5,'P' from dual
union all select 5,'F' from dual;


SQL

--■■■ドモルガンの法則で変形前■■■
select ID
  from AggTest
 group by ID
having
   not(count(*) = sum(decode(Val,'P',1,0))
       or (1 = all(max(decode(Val,'P',1,0)),max(decode(Val,'U',1,0)))
        and count(*) = sum(case when Val in('P','U') then 1 end)))
order by ID;

--■■■ドモルガンの法則で変形後■■■
select ID
  from AggTest
 group by ID
having
count(*) > sum(decode(Val,'P',1,0))
and (0 in (max(decode(Val,'P',1,0)),max(decode(Val,'U',1,0)))
 or count(*) > sum(case when Val in('P','U') then 1 end))
order by ID;

--■■■ブール代数の同値変形で変形■■■
select ID
  from AggTest
 group by ID
having
count(*) > sum(decode(Val,'P',1,0))
and 0 in (max(decode(Val,'P',1,0)),max(decode(Val,'U',1,0)))
 or count(*) > sum(case when Val in('P','U') then 1 end)
order by ID;


解説

count(*) = sum(decode(Val,'P',1,0)) をA
1 = all(max(decode(Val,'P',1,0)),max(decode(Val,'U',1,0))) をB
count(*) = sum(case when Val in('P','U') then 1 end) をC
とおくと

命題 A ⇒ C
が成り立つので
対偶である
_    _
C ⇒ A
も成り立ちます
2-2 命題が成立した状態での、論理積より
_   _   _
C * A = C
が成り立つので
_  _   _    _ _ _ _   _ _   _
A*(B + C) = A*B+A*C = A*B + C

といった
ブール代数の同値変形をしてます