7
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

SQLにおけるNULLの危険性 -実例で学ぶNULLの仕組み-

Last updated at Posted at 2018-08-01

対象読者

  • SQLでNOT INを使おうとしている方
  • SQLにおけるNULLの仕様を知りたい方

NOT INを使ってみる

前提となるテーブル

グループA

名前 都道府県
山田 千葉
田中 東京

グループB

名前 都道府県
アラン 千葉
イーサン 東京
ウィリアム 北海道
ベンジー 東京
ルーサー 東京

SQLを実行してみる

グループBの行のうち、グループAに存在しない都道府県の値を持つ行を取得する
この場合、北海道はグループAに含まれないため、ウィリアムがSQLの結果として抽出されるはずです。

SELECT * FROM group_b
WHERE prefecture NOT IN (SELECT prefecture FROM group_a);

実行結果

名前 都道府県
ウィリアム 北海道

期待通りの結果が出力されました。特に問題ないように思えます。しかし、 データにNULLがある場合はどうなるでしょうか。

前提となるテーブル(NULLあり)

グループAに対して、新たに鈴木さんを追加します。ただし、鈴木さんの都道府県はNULLとします。

グループA

名前 都道府県
山田 千葉
田中 東京
鈴木 NULL

グループB

名前 都道府県
アラン 千葉
イーサン 東京
ウィリアム 北海道
ベンジー 東京
ルーサー 東京

SQLを実行してみる(NULLあり)

先ほどとまったく同じSQLを実行してみます。

SELECT * FROM group_b
WHERE prefecture NOT IN (SELECT prefecture FROM group_a);

実行結果

名前 都道府県
   

な、なんと0件!!!
先ほどのウィリアムが出力されなくなっていしまいました。

なぜNULLがあると出力されなくなったのか

それは、このSELECT文でWHERE句の評価が一度もtrueとならなかったためです
SQLでは、WHERE句の評価結果がtrueになった行のみを処理対象とします。WHERE句がtrueにならなければSELECTの処理対象となりません。

なぜWHERE句がtrueにならないのか

雑な説明ですが考え方は以下の図の通りです。
グループAの都道府県列にNULLが1件でも存在する限り、WHERE句の評価結果は必ずunknownとなります。SQLを何度実行しようともWHERE句がtrueになることはないため、1行も処理対象として抽出されません。

覚えておくべきことは**「AND演算の中に1つでもunknownがあると、結果は絶対にtrueにならない」**ということです。NULLの仕様を理解しないと予期しない結果を出力するSQLを作ってしまうかもしれないので注意が必要です。

おまけ:解決策

  1. NOT EXISTSを使う
  2. NOT NULL制約を設ける
SELECT * FROM group_b bb
WHERE NOT EXISTS (SELECT * FROM group_a aa WHERE aa.prefecture = bb.prefecture);

解説は省略します。

7
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?