SQLを学び始めると、必ず出会うのが「NULL」という特別な値です。これはプログラミングにおける「null」や「None」とは少し異なる振る舞いをすることがあり、最初は戸惑うかもしれません。このセクションでは、SQLにおけるNULLの基本的な意味と、それを検索する方法について学びましょう!
NULLとは何か?🤔
NULLは、データベースのテーブルにおいて「値が存在しない」または「不明である」ことを示す特別なマーカーです。
重要なのは、NULLは 0
(ゼロ)や空文字列(''
)とは全く異なるということです。
- 0 (ゼロ): 数値としての「0」という具体的な値。
- 空文字列 (”): 長さ0の文字列データ。データ自体は存在します。
- NULL: データそのものが存在しない、または不明な状態。
例えば、ユーザー情報を管理するテーブルで、「誕生日」カラムがNULLになっている場合、それは「誕生日が1月0日」や「誕生日が空」という意味ではなく、「誕生日が登録されていない」または「誕生日が不明」ということを示します。
NULLの検索: IS NULL / IS NOT NULL ✨
NULLを検索する際に、最も注意すべき点があります。それは、通常の比較演算子(=
, <>
, !=
など)ではNULLを正しく判定できないということです。
例えば、「emailカラムがNULLのユーザーを探したい」と思って次のようなクエリを書いたとします。
-- これは意図した通りに動作しません! ❌
SELECT * FROM users WHERE email = NULL;
このクエリは、emailカラムがNULLのユーザーを返してくれません。なぜなら、SQLにおいてNULLは「値ではない」ため、NULL = NULL
という比較は常に「不明 (UNKNOWN)」と評価されるからです。同様に email <> NULL
や email != NULL
も意図通りには動作しません。
NULL値を正しく検索するためには、専用の演算子 IS NULL
と IS NOT NULL
を使用します。
IS NULL: NULLである行を検索
カラムの値がNULLである行を検索するには IS NULL
を使います。
-- emailカラムがNULLのユーザーを検索
SELECT user_id, name FROM users WHERE email IS NULL;
このクエリは、emailアドレスが登録されていない(NULLである)ユーザーのIDと名前を返します。
IS NOT NULL: NULLでない行を検索
逆に、カラムの値がNULLではない(何らかの値が入っている)行を検索するには IS NOT NULL
を使います。
-- 価格 (price) がNULLでない商品を検索
SELECT product_name, price FROM products WHERE price IS NOT NULL;
このクエリは、価格が設定されている(NULLではない)商品の名前と価格を返します。
IS NULL
または IS NOT NULL
を使いましょう! = NULL
や <> NULL
は使いません。
NULLと集計関数 📊
COUNT
, SUM
, AVG
などの集計関数を使う際にも、NULLの扱いに注意が必要です。基本的に、ほとんどの集計関数は計算の対象とするカラムの値がNULLである場合、その行を無視します。
関数 | NULLの扱い | 例 |
---|---|---|
COUNT(*) |
NULLを含むすべての行数をカウントします。 | SELECT COUNT(*) FROM users; |
COUNT(列名) |
指定した列の値がNULLでない行数をカウントします。 | SELECT COUNT(email) FROM users; (emailがNULLの行はカウントされない) |
SUM(列名) |
NULLを無視して合計値を計算します。 | SELECT SUM(score) FROM results; (scoreがNULLの行は合計に含まれない) |
AVG(列名) |
NULLを無視して平均値を計算します。(合計値 ÷ NULLでない行数) | SELECT AVG(age) FROM members; (ageがNULLの行は平均計算の母数にも分子にも含まれない) |
MIN(列名) |
NULLを無視して最小値を検索します。 | SELECT MIN(price) FROM products; |
MAX(列名) |
NULLを無視して最大値を検索します。 | SELECT MAX(salary) FROM employees; |
注意点:
COUNT(*)
だけは特別で、行全体を見るためNULLかどうかに関わらずカウントします。SUM
やAVG
などで、NULLを0として扱って計算したい場合は、COALESCE
やIFNULL
といった関数を使ってNULLを0に変換する必要があります(これらの関数は別の機会に詳しく学びます)。例えば、AVG(COALESCE(score, 0))
のように使います。- 全ての値がNULLのカラムに対して
SUM
やAVG
を適用した場合、結果がNULLになることがあります(データベースによって挙動が異なる場合があります)。COUNT
は0を返します。
NULLとソート (ORDER BY) ⬆️⬇️
ORDER BY
句を使って結果を並び替える際、NULL値がどのように扱われるかは、使用しているデータベースシステム(MySQL, PostgreSQL, SQL Serverなど)によってデフォルトの挙動が異なります。
- PostgreSQL, Oracle: デフォルトでは、昇順(
ASC
)の場合はNULLが最後に、降順(DESC
)の場合はNULLが最初に来ます。 - MySQL, SQL Server, SQLite: デフォルトでは、昇順(
ASC
)の場合はNULLが最初に、降順(DESC
)の場合はNULLが最後に来ます。
SQL標準では、NULLS FIRST
または NULLS LAST
を ORDER BY
句に追加することで、NULLの順序を明示的に指定できます。これにより、データベース間の挙動の違いを吸収できます。(ただし、MySQLの古いバージョンなど、一部のデータベースではこの構文がサポートされていない場合があります。)
-- PostgreSQL, Oracle などで NULL を最初に持ってくる例
SELECT name, registration_date
FROM users
ORDER BY registration_date ASC NULLS FIRST;
-- PostgreSQL, Oracle などで NULL を最後に持ってくる例
SELECT name, registration_date
FROM users
ORDER BY registration_date DESC NULLS LAST;
NULLS FIRST
/ NULLS LAST
が使えないデータベース(例: MySQL)では、少し工夫が必要になることがあります。例えば、IS NULL
を使ってNULLかどうかを先に判定させる方法があります。
-- MySQL で NULL を最後に持ってくる例 (昇順の場合)
SELECT name, registration_date
FROM users
ORDER BY registration_date IS NULL ASC, registration_date ASC;
-- registration_date IS NULL は NULL なら 1, そうでなければ 0 を返すので、先に 0 (非NULL) が来て、次に 1 (NULL) が来る
-- MySQL で NULL を最初に持ってくる例 (降順の場合)
SELECT name, registration_date
FROM users
ORDER BY registration_date IS NULL DESC, registration_date DESC;
-- registration_date IS NULL は NULL なら 1, そうでなければ 0 を返すので、先に 1 (NULL) が来て、次に 0 (非NULL) が来る
あるいは、MySQLでは-
(マイナス記号)を使ってソート順を反転させるテクニックもありますが、少し直感的ではないかもしれません。
ORDER BY
を使う際は、NULLがどのようにソートされるか、データベースのドキュメントを確認するか、NULLS FIRST
/ NULLS LAST
(対応していれば) を使って明示的に指定するのが安全です。
まとめ 🎉
今回はNULLの扱いについて学びました。
- ✅ NULLは「値がない」「不明」を示す特別なマーカーであり、0や空文字列とは異なります。
- ✅ NULLを検索するには
=
や<>
ではなく、IS NULL
またはIS NOT NULL
を使用します。 - ✅ ほとんどの集計関数 (
SUM
,AVG
,MIN
,MAX
,COUNT(列名)
) は、計算時にNULL値を無視します。COUNT(*)
はNULLもカウントします。 - ✅
ORDER BY
でのNULLの扱いはデータベースによって異なるため、NULLS FIRST
/NULLS LAST
で明示的に指定するか、挙動を確認しましょう。
NULLはSQLを扱う上で非常に重要で、時に予期せぬ結果の原因にもなります。このセクションで学んだ基本をしっかり押さえて、NULLと上手に付き合っていきましょう!💪
コメント