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

8-2 case式でis not falseを模倣

SQLパズル

以下のSQLをOracle9iのSQLで記述する(?はバインド変数)

select UserID,EntryDay,age from Table_Name
where
(
        UserID = ?
    and EntryDay = ?
    and age >= ?
    and age < ?
) is not false
order by UserID;

こちらを参考にさせていただきました


データ作成スクリプト

create table Table_Name(
UserID   number(1),
EntryDay Date,
age      number(3));

insert into Table_Name values(1,to_date('20050101','yyyymmdd'),20);
insert into Table_Name values(2,to_date('20050201','yyyymmdd'),25);
insert into Table_Name values(3,to_date('20050301','yyyymmdd'),30);
insert into Table_Name values(4,to_date('20050401','yyyymmdd'),35);
insert into Table_Name values(5,to_date('20050501','yyyymmdd'),40);
insert into Table_Name values(null,null,45);
commit;


SQL

--■■■case式を使用■■■
select UserID,EntryDay,age from Table_Name
where case when not (
        UserID = ?
    and EntryDay = ?
    and age >= ?
    and age < ?
) then 1 else 0 end =0
order by UserID;

--■■■スカラー問い合わせを使用■■■
select UserID,EntryDay,age from Table_Name
where (select count(*) from dual where not (
        UserID = ?
    and EntryDay = ?
    and age >= ?
    and age < ?
)) =0
order by UserID;

--■■■unknownとの論理積を調べる方法(Oracleだとエラーになるようです)■■■
--select UserID,EntryDay,age from Table_Name
-- where ((UserID = ?
--     and EntryDay = ?
--     and age >= ?
--     and age < ?) and null = null) is null
--order by UserID;


実行例

select UserID,EntryDay,age from Table_Name
where case when not (
        UserID = null
    and EntryDay = null
    and age >= null
    and age < null
) then 1 else 0 end =0
order by UserID;

select UserID,EntryDay,age from Table_Name
where case when not (
        UserID = null
    and EntryDay = to_date('20050401','yyyymmdd')
    and age >= null
    and age < null
) then 1 else 0 end =0
order by UserID;

select UserID,EntryDay,age from Table_Name
where case when not (
        UserID = null
    and EntryDay = null
    and age >= 20
    and age < 30
) then 1 else 0 end =0
order by UserID;

select UserID,EntryDay,age from Table_Name
where (select count(*) from dual where not (
        UserID = null
    and EntryDay = null
    and age >= 20
    and age < 30
)) =0
order by UserID;


解説

case式や、スカラー問い合わせで、
is not falseを模倣できます。

検索対象のカラムがNULLだと、検索条件を指定しても、
その行はヒットする点に注意する必要があります。

■■■■■■■■■■■■■■■■■■■■■■■■■■■■
(条件A) is not false ⇔ (not(条件A)) is not true
という論理を使ってます

(条件A) is not false ⇔ (not(条件A)) is not true の証明

not(true) = false
not(unknown) = unknown
not(false) = true
より

条件Aがtrue ⇒ not(条件A)がfalse
条件Aがunknown ⇒ not(条件A)がunknown
条件Aがfalse ⇒ not(条件A)がtrue

条件Aがtrue、条件Aがfalse、条件Aがunknownは、
全ての場合を網羅している。(和集合が全体集合)

(not 条件X)がfalse、(not 条件X)がtrue、(not 条件X)がunknownは、
どの2つも両立しない(どの2つの共通集合も空集合)

よって、転換法より、逆も真となるので、

条件Aがtrue ⇔ not(条件A)がfalse
条件Aがunknown ⇔ not(条件A)がunknown
条件Aがfalse ⇔ not(条件A)がtrue

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

条件A is not false
⇔ (条件A が true) または (条件A が unknown)
⇔ ((not 条件A)がfalse) または ((not 条件A)がunknown)

not 条件Aを、条件B
とおいて

⇔ ((not 条件A)がfalse) または ((not 条件A)がunknown)
⇔ (条件Bがfalse) または (条件Bがunknown)
⇔ 条件B is not true

よって
条件A is not false ⇔ (not 条件A) is not true

そして、not(条件A)
を、検索case式のwhen句で使ってます。

2-2-11 case式とLNNVL述語
10-155 is not trueとis not falseを模倣

NULL、Unknown、3値論理
3値論理 ―― 神のいない論理
3値論理とNULL:CodeZine

BOOLEAN型の資料

証明 - Wikipedia
対偶証明法と背理法
【第77回】転換法