[SQLのはじめ方] Part11: NULLの扱いとIS NULL/IS NOT NULL

SQL

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 <> NULLemail != NULL も意図通りには動作しません。

NULL値を正しく検索するためには、専用の演算子 IS NULLIS 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ではない)商品の名前と価格を返します。

ポイント: 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かどうかに関わらずカウントします。
  • SUMAVG などで、NULLを0として扱って計算したい場合は、COALESCEIFNULL といった関数を使ってNULLを0に変換する必要があります(これらの関数は別の機会に詳しく学びます)。例えば、AVG(COALESCE(score, 0)) のように使います。
  • 全ての値がNULLのカラムに対して SUMAVG を適用した場合、結果が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 LASTORDER 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と上手に付き合っていきましょう!💪

コメント

タイトルとURLをコピーしました