未登録と 0 件を正しく表示する
すべての顧客について「顧客名, 都道府県, 受注件数」を出してください。都道府県(pref)が未登録の顧客は「未登録」と表示します。受注件数は取消されていない受注(status が 'done')だけを数え、1 件も無い顧客は 0 と表示します。顧客番号(kokyaku_id)の小さい順に並べてください。
主要 7 製品で通用 そのまま使える: PostgreSQL / MySQL / MariaDB / SQLite / SQL Server / Oracle Database / IBM Db2
- COALESCE は引数を左から見て、最初に NULL でない値を返します。
- NVL(Oracle)や ISNULL(SQL Server)といった独自の関数もありますが、COALESCE なら書き換えずに済みます。
- count(列) は NULL を数えません。LEFT JOIN で相手がいなかった行を 0 と数えたいときに効いてきます。
この問題で使えるテーブル(名前をタップすると入力できます)
10 行
| 列 | 型 | NULL |
|---|---|---|
| 🔑 | int | 不可 |
| int | 不可 | |
| date | 不可 | |
| text | 不可 |
データを見る(先頭 5 行)
| juchu_id | kokyaku_id | juchu_on | status |
|---|---|---|---|
| 1001 | 1 | 2025-11-05 | done |
| 1002 | 2 | 2025-11-18 | done |
| 1003 | 1 | 2025-12-02 | done |
| 1004 | 3 | 2025-12-09 | cancel |
| 1005 | 4 | 2025-12-24 | done |
17 行
| 列 | 型 | NULL |
|---|---|---|
| 🔑 | int | 不可 |
| 🔑 | int | 不可 |
| int | 不可 | |
| int | 不可 | |
| numeric(10,0) | 不可 |
データを見る(先頭 5 行)
| juchu_id | gyo_no | shohin_id | suryo | tanka |
|---|---|---|---|---|
| 1001 | 1 | 1 | 20 | 180 |
| 1001 | 2 | 2 | 30 | 120 |
| 1002 | 1 | 4 | 2 | 23800 |
| 1002 | 2 | 5 | 1 | 18500 |
| 1003 | 1 | 6 | 4 | 4200 |
5 行
| 列 | 型 | NULL |
|---|---|---|
| 🔑 | int | 不可 |
| text | 不可 | |
| text | 可 | |
| date | 不可 |
データを見る(先頭 5 行)
| kokyaku_id | kokyaku_name | pref | created_on |
|---|---|---|---|
| 1 | 青葉工業 | 東京都 | 2024-05-10 |
| 2 | 白樺物産 | 大阪府 | 2024-08-01 |
| 3 | 黒松システム | 東京都 | 2025-01-15 |
| 4 | 赤坂商会 | NULL | 2025-03-20 |
| 5 | 三田商事 | 愛知県 | 2025-06-01 |
7 行
| 列 | 型 | NULL |
|---|---|---|
| 🔑 | int | 不可 |
| text | 不可 | |
| text | 不可 | |
| numeric(10,0) | 不可 |
データを見る(先頭 5 行)
| shohin_id | shohin_name | category | price |
|---|---|---|---|
| 1 | ノート | 文具 | 180 |
| 2 | ボールペン | 文具 | 120 |
| 3 | 付箋 | 文具 | 250 |
| 4 | デスクチェア | 家具 | 24800 |
| 5 | 書棚 | 家具 | 18500 |
解説
結論
NULL の置き換えは COALESCE(列, 代わりの値)。件数を 0 と出したいときは、外部結合+条件を ON 側+count(列) の 3 点セットです。
なぜ COALESCE か: NULL は「値が無い」ことを表す特別な状態で、値ではありません。そのため = NULL では判定できません(結果は真でも偽でもなく「不明」になります)。判定するなら IS NULL、置き換えるなら COALESCE を使います。
★条件を ON に書くか WHERE に書くか: これがこの問題の核心です。LEFT JOIN は「右側に相手がいなくても左側の行を残す」働きをしますが、WHERE は結合が終わったあとに働きます。相手がいない行は右側の列がすべて NULL になっているので、WHERE j.status = 'done' を通すと、そこで消えてしまいます。「左側の行を残したまま右側を絞りたい」なら、条件は ON 側に書きます。
★count(*) と count(列) の違い: count(*) は行を数えます。外部結合で相手がいなかった行も 1 行なので、1 と数えてしまいます。count(j.juchu_id) は NULL を数えないため、相手がいなかった行は 0 になります。「0 件を 0 と出す」ためには count(列) が必要です。
よくある間違い
①絞り込みの条件を WHERE に書いて外側の行を消す。②count(*) を使って 0 が 1 になる。③= NULL で判定しようとする。
根拠(一次情報)
- PostgreSQL 18 マニュアル: 条件式(COALESCE)一次情報・確認 2026-07-28
- PostgreSQL 18 マニュアル: 集約関数(count の扱い)一次情報・確認 2026-07-28
- PostgreSQL 18 マニュアル: 結合(ON と WHERE の違い)一次情報・確認 2026-07-28