いきなりですが問題です
Q1
SELECT * FROM users WHERE nickname = NULL;
nicknameがNULLのユーザーは取れますか?
Q2
SELECT * FROM users WHERE nickname != 'nori';
nicknameがNULLのユーザーは取れますか?
Q3
SELECT * FROM users WHERE 1 = 1;
上記のSQLは1 = 1がtrueになるため、全てのレコードが取得されます。
SELECT * FROM users WHERE NULL = NULL;
上記の場合、全レコードが取得できますか?
Q4
SELECT GREATEST(30, 50, NULL);
GREATESTは引数の中の最大値を返す関数です。今回の場合どのような値が取得できますか?
テーブルを作るなら
実際にSQLでやってみたいという人は以下のSQLを使うとそれっぽいことができます
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(100),
age INT,
nickname VARCHAR(100)
);
INSERT INTO users VALUES (1, 'John', 30, 'manjiro');
INSERT INTO users VALUES (2, 'Pine', 50, 'piko');
INSERT INTO users VALUES (3, 'Mike', NULL, NULL);
実行環境もほしいよという欲張りさんはSQL Playgroundを使うといいんじゃないかな
答え合わせ
さて、答え合わせをしていきましょう。
Q1
SELECT * FROM users WHERE nickname = NULL;
nicknameがNULLのユーザーは取得できますか?
→できません
Q2
SELECT * FROM users WHERE nickname != 'nori';
nicknameがNULLのユーザーは取得できますか?
→できません
Q3
SELECT * FROM users WHERE 1 = 1;
上記のSQLは1 = 1がtrueになるため、全てのレコードが取得されます。
SELECT * FROM users WHERE NULL = NULL;
上記の場合、全レコードが取得できますか?
→できません
Q4
SELECT GREATEST(30, 50, NULL);
GREATESTは引数の中の最大値を返す関数です。今回の場合どのような値が取得できますか?
→NULL
※ちなみにPostgreSQLだけは他のRDBMSと違う動きをしており、50が取得されます
さて…
全問納得の結果でしたか?
もしそうならこの記事から学べることはないので、有意義な時間を過ごすためにも今すぐPCを閉じて筋肉を鍛えましょう。
もし間違えたり、合ってたけど腑に落ちないところがある方は、後ろの内容を読むと有益な情報を得られるかもしれません。
SQLにおいてNULLとは?
いきなり愚痴っぽくなるんですけどNULLって絶妙に理解しにくいですよね。
なんとなく「ない」とか「未定」とか「適用不能」とか「空」とか「不明」とか、ちょっと存在怪しげなニュアンスなのはわかるけど、ちゃんと言語化しようと思ったら曖昧になりがちな概念だと思います。
しかし、SQLにおけるNULLには明確な意味があるんです…
それは「不明」という意味です
つまるところ明確に不明というわけなんです!
あ、帰らないでください。
真偽値の3値理論
3値理論の前に2値理論から見てみましょう。
一般的なプログラミング言語は2値理論を採用しています。
ある命題について真か偽かで表すやつです。
要は普通のBooleanですね。
一方SQLで採用されている3値理論というのは、真偽に加えて不明という値を加えたもののことをいいます。
そしてNULLに不明がアサインされています。
このNULLが不明であるという気持ちを持ったまま、さっきの問題を見ると全てが腑に落ちます。
Q1
SELECT * FROM users WHERE nickname = NULL;
=は等しいかどうかをチェックする演算子ですが、nicknameの文字が不明と等しいかどうかはわかりません。
そのため、その比較結果がTRUEにならずレコードを取得できません。
NULLの値を検索する場合、IS NULLというキーワードを使いますが、これはその値が不明であるかどうかをチェックするキーワードだから、NULLが見つかります。
値が不明と同じかはわからないけど、不明であることはわかるということです。
Q2
SELECT * FROM users WHERE nickname != 'nori';
これもQ1と同様ですが、不明な値なので、noriという文字列と一致していないかどうかは不明なのです。
その結果、TRUEと判定できず、レコードが取得できません。
ちなみにこれは大名著「SQLアンチパターン」のフィアオブジアンノウンの章で紹介されています。
Q3
SELECT * FROM users WHERE NULL = NULL;
不明と不明のものを比較しても同じかどうかは判定できないですね。
例えるなら中身が見えない箱を2つ出されて、これの中身は同じですか?と聞かれているようなものです。
なので、この場合もレコードは取得できません。
Q4
SELECT GREATEST(30, 50, NULL);
30と50と不明、どれが一番大きいですか?
50か不明なのはわかりますが、確信は持てないですね。
なので結果も不明を表すNULLになります。
NULLに対して「何もない」みたいな認識を持ってしまうと50が取れそうな雰囲気を感じ取ってしまいますね。
ちなみにこのときNULLを0みたいに扱いたければ、COALESCE関数を使って以下のように書いてあげるといい感じに動いてくれます。
SELECT GREATEST(30, 50, COALESCE(NULL, 0));
結論
SQLにおいてNULLはトリッキーな動きをするが、NULLは不明という意識を持っておくとだいたい腑に落ちる
ということで3値理論を肝に命じて楽しいSQLライフを送りましょう。