CodeGym /コース /SQL SELF /データ結合時の NULL値の扱い方

データ結合時の NULL値の扱い方

SQL SELF
レベル 12, レッスン 0
使用可能

例えば、students(学生)テーブルとenrollments(コース登録)テーブルを結合するとしよう。もしenrollmentsテーブルにある学生の情報がなかったとしても、例えばLEFT JOINを使えば、studentsテーブルの行はちゃんと出てくるけど、enrollmentsの情報は抜けてる。その場合、具体的なデータの代わりにNULLが出てくるんだ。

こんな感じになるよ:

studentsテーブル:

id name
1 Eva
2 Peter
3 Anna

enrollmentsテーブル:

student_id course_name
1 数学
1 情報科学
2 物理

LEFT JOINを使ったクエリ:

SELECT students.id, students.name, enrollments.course_name
FROM students
LEFT JOIN enrollments ON students.id = enrollments.student_id;

結果:

id name course_name
1 Eva 数学
1 Eva 情報科学
2 Peter 物理
3 Anna NULL

やあ、NULL!見ての通り、Annaはどのコースにも登録してないから、コース情報がなくて、何もない代わりにNULLが出てくる。

NULLはクエリにどう影響する?

NULLは「ゼロ」でも「空文字」でもなくて、値がないってこと。これがいろいろ面白い(時にはイラっとする)影響をもたらすんだ:

NULLとの比較:

例えばWHERE course_name = NULLみたいに書いても、NULLの行は返ってこない。なぜかって?NULLは直接比較できないから。

NULLがあるかどうか調べるには、専用の演算子を使う必要がある:

WHERE course_name IS NULL

数学演算:

NULLを使った演算は全部NULLになる。例えば:

SELECT 5 + NULL; -- 結果: NULL

集約関数:

SUM()やAVG()みたいな集約関数はNULLを無視するけど、COUNT(*)は「存在する行」としてカウントするよ。

NULLとどう付き合う?

  1. COALESCE()でNULLを分かりやすい値に置き換える

COALESCE()関数を使えば、NULLを他の値に変えられる。例えば、コースがなかったら"コースなし"って表示したいとき:

SELECT
    students.id, 
    students.name, 
    COALESCE(enrollments.course_name, 'コースなし') AS course_name
FROM 
    students LEFT JOIN enrollments 
    ON students.id = enrollments.student_id;

結果:

id name course_name
1 Eva 数学
1 Eva 情報科学
2 Peter 物理
3 Anna コースなし

これでだいぶ見やすくなったよね?

  1. NULL値のフィルタリング

NULLの行を見たくないなら、WHERE ... IS NOT NULLを使えばOK。例えば:

SELECT
    students.id, 
    students.name, 
    enrollments.course_name
FROM 
    students LEFT JOIN enrollments 
    ON students.id = enrollments.student_id
WHERE 
    enrollments.course_name IS NOT NULL;

結果:

id name course_name
1 Eva 数学
1 Eva 情報科学
2 Peter 物理

Annaは結果から消える。なぜなら彼女はコース登録がないから。

  1. NULLを考慮したカウント:COUNTの例

さっきも言ったけど、関数によってNULLの扱いが違う。例えば:

全部の行をカウントしたい(course_nameがNULLでも):

SELECT COUNT(*) FROM students; -- 全部の行をカウント(`course_name` = NULLも含む)

NULLじゃない行だけカウントしたいとき:

SELECT COUNT(course_name) FROM enrollments;
  1. CASEで条件分岐

COALESCE()がイマイチだったり、もっと柔軟にやりたいならCASEを使ってみて。例えば:

SELECT
    students.id, 
    students.name,
    CASE
        WHEN enrollments.course_name IS NULL THEN 'コースなし'
        ELSE enrollments.course_name
    END AS course_name
FROM 
    students LEFT JOIN enrollments 
    ON students.id = enrollments.student_id;

結果はCOALESCE()と同じになるけど、CASEならもっと複雑なルールも書けるよ。

  1. NULLが絶対にないならINNER JOINを使おう

一番シンプルにNULLを避ける方法は、そもそもNULLが出ないようにINNER JOINを使うこと。これは両方のテーブルにマッチする行だけ返すJOINだよ:

SELECT
    students.id, 
    students.name, 
    enrollments.course_name
FROM 
    students INNER JOIN enrollments 
    ON students.id = enrollments.student_id;

サプライズなし!コース登録してる学生だけが出てくる。

結果:

id name course_name
1 Eva 数学
1 Eva 情報科学
2 Peter 物理

もし全部のデータ(NULLも含めて)を見せたいならINNER JOINは向いてないけど、必要なときはこれで十分!

2
タスク
SQL SELF, レベル 12, レッスン 0
ロック未解除
`COALESCE` を使って `NULL` 値を置き換える
`COALESCE` を使って `NULL` 値を置き換える
2
タスク
SQL SELF, レベル 12, レッスン 0
ロック未解除
コース未登録の学生のカウント(`COUNT`の使用)
コース未登録の学生のカウント(`COUNT`の使用)
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION