よくあるSQLのミスと対処

初学者がやりがちなSQLのミスを、原因と対処法つきでまとめます。NULLの比較、GROUP BYの列指定、暗黙の型変換、JOINでの行の重複など、つまずきやすいポイントを一覧で整理します。

SQL は書けるようになっても、思った結果にならないことがあります。その多くは「よくあるパターン」に当てはまります。ここでは初学者がつまずきやすいミスを、原因と対処つきで整理します。一度知っておくと、同じ失敗を避けられます。

1. NULL を = で比較してしまう

query.sql
WHERE phone = NULL   -- 一件も返らない

NULL との = 比較は結果が「不明」になり、条件を満たしません。IS NULL / IS NOT NULL を使います。

query.sql
WHERE phone IS NULL

2. NOT IN とサブクエリの NULL

NOT IN のサブクエリ結果に NULL が混ざると、何も返らないことがあります。

query.sql
WHERE id NOT IN (SELECT customer_id FROM orders)  -- orders に NULL があると危険

customer_id に NULL が含まれると、SQL の論理上すべての比較が「不明」になり、結果が空になります。安全なのは NOT EXISTS を使うことです。

query.sql
WHERE NOT EXISTS (
  SELECT 1 FROM orders o WHERE o.customer_id = customers.id
)

3. GROUP BY に列を書き忘れる

集約と一緒に、集約していない列を SELECT に書くとエラーになります。

query.sql
SELECT dept, name, AVG(salary)   -- name が問題
FROM employees
GROUP BY dept;

GROUP BY dept でまとめると、1 つの部門に複数の name があり、どれを返すか決まりません。SELECT に出せるのは GROUP BY の列か集約関数だけです。name を出したいなら、そもそも集約が適切かを見直します。

4. 集約関数を WHERE に書く

query.sql
WHERE COUNT(*) > 1   -- エラー

集約結果で絞りたいときは WHERE ではなく HAVING を使います(集約は WHERE より後に評価されるため)。

query.sql
GROUP BY customer_id
HAVING COUNT(*) > 1

5. JOIN で行が意図せず増える

JOIN した結果、行数が想定より増えることがあります。これは結合先に該当行が複数あるためです。たとえば 1 件の注文に複数の明細があると、注文 × 明細の数だけ行が生成されます。

対処は、(a) 何を 1 行としたいかを明確にする、(b) 必要なら集約(GROUP BYSUM など)でまとめる、です。「JOIN したら件数が合わない」と感じたら、結合の粒度を疑いましょう。

6. 整数どうしの割り算

query.sql
SELECT 5 / 2;   -- 2(小数点以下が切り捨て)

整数どうしの割り算は、小数点以下が切り捨てられることがあります。小数で欲しいときは、どちらかを小数にします。

query.sql
SELECT 5.0 / 2;              -- 2.5
SELECT CAST(5 AS numeric) / 2;

7. 文字列の大文字・小文字

WHERE name = 'alice' は、データが 'Alice' だと一致しません(多くのデータベースは既定で大文字小文字を区別します)。大小を無視して比較したいときは、両辺を揃えます。

query.sql
WHERE LOWER(name) = 'alice'

まとめ

よくあるミスは、たいてい次のどれかに根ざしています。

  • NULL の特殊な振る舞い(比較・NOT IN)
  • 集約のルール(GROUP BY の列、WHERE と HAVING)
  • JOIN の粒度(行の増加)
  • 型の扱い(整数割り算、大文字小文字)

「思った結果にならない」ときは、この一覧に当てはまっていないか確認してみてください。原因が分かれば、対処はシンプルです。

手を動かして確認しましょうブラウザ上で SQL を書いて実行・自動採点できる演習問題に挑戦できます。
問題一覧へ →