0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

WHERE句で「NOT LIKE 'masked-%'」なのにNULLが引っかからない話

Posted at

クイズ

以下のクエリを実行すると、何件のレコードが返ってくるでしょうか?

SELECT COUNT(*) 
FROM users 
WHERE email NOT LIKE 'mask-%';

usersテーブル

id email
1 'kuzuba@example.com'
2 'mask-abc'
3 NULL

答え: 1件

「NULLはmask-で始まらないから2件じゃないの?」と思った方のために、この記事を書こうと思います。僕も実務でWHERE句を書いていて、ふと思った時があったので簡単にまとめます。

NULLとは何か

値ではなく「状態」

NULLは値が不明である状態であることを表します。

クエリを実行すると以下のように判断されます。

email = 'kuzuba@example.com'  --→ 「値がある」と解釈する
email = ''                     --→ 「値がある(空文字だけど)」と解釈する
email = NULL                   --→ 「不明(値がないのではなく)」と解釈する

NULLは、値がないのではなく「不明」と解釈される

空文字との違い

空文字とは明確に違いがあるので、まとめておきます。

項目 空文字 '' NULL
意味 「空っぽ」という値 値が不明
比較 = '' で判定可能 IS NULL が必要
文字数 0文字 不明

なぜNOT LIKEで引っかからないのか

SQLの3値論理

SQLは値が何かを判断する時、

  • 1.TRUE
  • 2.FALSE
  • 3.UNKNOWN(不明)

という3つの状態に分けます。

NULLがくると、箱を開けてみないと何が入っているか分からない、、、だから中身は知らない!という意味でUNKNOWNとします。

具体的には以下のようになります。

NULL = NULL     
NULL != NULL
--→ 不明なので一緒かどうかも判定できないのでUNKNOWNと解釈する

NULL > 10
--→ 10より大きいのか判定できないのでUNKNOWNと解釈する

WHERE句の評価ルール

最初のクイズに戻りますが、
WHERE句では、TRUEになったレコードだけを絞り込むので、

WHERE email NOT LIKE 'mask-%'

は以下のように判定します。

'kuzuba@example.com'  TRUE(返す)
'mask-abc'            FALSE(返さない)
 NULL                 UNKNOWN(返さない)

人間の直感では「NULLはmask-で始まらないんだからTRUEでしょ」と思いたくなりますが、データベースはもっと慎重に判断すると思っておくと良さそうです。

じゃ、クエリ書く時はどうするのか

マスクされていないデータを検出したいとき、NULLのレコードも「マスクされていない」として扱いたい場合があります。
そんなときは、OR email IS NULLをつけて明示的に追加します。

NULLも含めて「mask-」として検出したい時

WHERE (email NOT LIKE 'mask-%' OR email IS NULL)

これで、'kuzuba@example.com'のような通常の値も、NULLも両方検出できます。

参考文献

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?