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?

SQLの NOT IN はなぜ NULL があると動かなくなるのか

Posted at

前提データ

問題のSQLを実行するためのINSERT文を以下に示します。

CREATE TABLE users (
    id INT
);

INSERT INTO users (id) VALUES
  (1),
  (2),
  (3),
  (NULL),
  (5);

簡易的に確認したい場合は以下のサイトを利用することをお勧めします。

問題のSQL

-- 連番になっていないIDを探したい
SELECT MIN(id + 1) AS notseq
FROM users
WHERE ( id + 1 ) NOT IN (SELECT id FROM users);

原因:NOT IN と NULL

NULLは比較することができない

SQLにおいてNULLは、

  • 空文字ではない
  • 0ではない
  • 不正値ではない

という「分からない」という状態を示しています。
つまり、値ではありません。

NOT INは比較する関数である

NOT INはある値xと別の値yを比較する仕組みになっています。
そのため、値ではないNULLが含まれてしまうと実行エラーにはならないものの、
条件がすべて UNKNOWN となり、結果がnullになります。

image.png

イメージとしては、

  • x = NULLは動かない
  • x IS NULLは動く

という仕組みと同じですね。
=は比較する時に使用する演算子なので、比較できないNULLを=で比較することはできないのです。

三値論理について知ると理解が深まる

SQLの世界では、三値論理を採用しています。

意味
TRUE 条件成立
FALSE 条件不成立
UNKNOWN 不明

この3つめに存在しているUNKNOWNを生み出すのがNULLです。

比較時のイメージ

NULLは何と比較してもUNKNOWNになってしまいます。

10 = 10      → TRUE
10 = 20      → FALSE
10 = NULL    → UNKNOWN
10 <> NULL   → UNKNOWN

回避方法

回避方法はNOT EXISTSを利用することです。
NOT INは比較してしまうことでエラーの原因になりました。
ですが、NOT EXISTSは値同士で比較しません。

NOT EXISTSは「この条件を満たすレコードが1行でも存在するか?」を判別します。
そのため、値同士による比較を行いません。その結果、NULLがあるカラムを抽出する際にNULLを許容することができます。

結論:NOT EXISTS を使う

問題のSQLをNOT EXISTSを利用することで問題を回避してみましょう。

SELECT MIN(u1.id + 1) AS notseq
FROM users u1
WHERE NOT EXISTS (
    SELECT 1
    FROM users u2
    WHERE u2.id = u1.id + 1
);

image.png

参考文系

  • 達人に学ぶSQL徹底指南書 第2版 初級者で終わりたくないあなたへ(著者:ミック)
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?