SQLではNULLの取り扱いに要注意 その2

前回、NULLが値でないこと・NULLと比較述語を組み合わせた場合の動作について書きました。

今回は、前回の内容もとに、何となくNULLを扱ってしまうことで起こる問題点と解決策を

以下の例をもとに、書いてみようと思います。

  • Aクラス(CLASS_A)
USER_ID AGE
1 25
2 30
3 35

 

  • Bクラス(CLASS_B)
USER_ID AGE
4 30
5 25
6 NULL

 

  • 条件
    1. 年齢は必須入力でないため、NULLで登録されることがあり得る。
    2. 同じユーザーがAクラス・Bクラスに同時に属することはない。

こんな感じのテーブルから、クラスBの誰とも年齢が一致しない、クラスAのユーザ一覧を

取得してみようと思います。

本来ならユーザ3は、クラスBの誰とも年齢が一致しないので

ユーザ3のレコードが取得できそうですが、こんな感じのSQLを書いてしまうと取得することができません。

 

正しく取得できない理由は、SQL文が以下のような順で評価されるためです。
(長くなるので、以下の例ではWHERE句以降のみを抜粋)

  1. CLASS_Bに関するSQLを展開
  2. WHERE句を展開
  3. WHERE句にド・モルガンの法則を適用
  4. NULLと比較述語を組み合わせると、UNKNOWNと評価される。
  5. ANDとUNKNOWNが組み合わさると、FALSEに評価される。

4.となる理由がわからない方は前回のブログを、

5.がわからない方はクリーネの3値論理 真理値表を見ていただければと思います。

対応策1

そもそも年齢がNULLのレコードは、検索結果に含める必要性がないため、検索条件を変更します。

 

ただこれだと、検索条件の漏れが起こってしまうため、イマイチな気がします。

対応策2

サブクエリ部分(CLASS_Bに関するSQL)部分が先に評価されることを防ぐため、

NOT INをNOT EXISTSに置き換えます。

対応策1で起こる検索条件の漏れを防ぐことができますので、個人的にはこちらがお勧めです。

 

以上。