あまり生のsqlを書かなくなり、ちょっとしたことでAIに聞いてみたら、
さらっと暗黙的なJoinが修正されてちょっとした気づきを得たので、
暗黙的なJOINの問題と改善したものにメモ的に残します。
暗黙的なJOINとは
暗黙的なJOINは、FROM句で複数のテーブルを,
で区切り、WHERE句で結合条件を書く古い書き方です。
例:暗黙的なJOIN(古い書き方)
SELECT e.name, d.department_name
FROM employees e, departments d
WHERE e.department_id = d.department_id
AND e.salary > 500000;
暗黙的なJOINの問題点
1. 可読性が低い
- 結合条件とフィルタ条件が混在してWHERE句が複雑になる
- どのテーブル同士が結合されているかが分かりにくい
2. メンテナンスが困難
- 複数のテーブルが関わると、どれが結合条件でどれがフィルタ条件か判別しづらい
- 結合条件を忘れやすく、意図しないクロス結合(デカルト積)が発生する危険性
3. 外部結合が書けない
- LEFT JOIN、RIGHT JOIN、FULL OUTER JOINが表現できない
4. エラーが発見しにくい
-- 結合条件を忘れた場合(危険!)
SELECT e.name, d.department_name
FROM employees e, departments d
WHERE e.salary > 500000; -- 結合条件なし → クロス結合
モダンなSQL(推奨される書き方)
1. 明示的なJOIN
-- 上記の例をモダンに書き直し
SELECT e.name, d.department_name
FROM employees e
INNER JOIN departments d ON e.department_id = d.department_id
WHERE e.salary > 500000;
2. 外部結合も明確に表現可能
-- 部署に所属していない従業員も含める
SELECT e.name, COALESCE(d.department_name, 'No Department')
FROM employees e
LEFT JOIN departments d ON e.department_id = d.department_id
WHERE e.salary > 500000;
3. 複数テーブルの結合も読みやすい
SELECT e.name, d.department_name, p.project_name
FROM employees e
INNER JOIN departments d ON e.department_id = d.department_id
INNER JOIN employee_projects ep ON e.employee_id = ep.employee_id
INNER JOIN projects p ON ep.project_id = p.project_id
WHERE e.salary > 500000
AND p.status = 'ACTIVE';
モダンなSQLのベストプラクティス
1. JOINの種類を明示
-- 良い例
INNER JOIN departments d ON e.department_id = d.department_id
LEFT JOIN addresses a ON e.employee_id = a.employee_id
-- 避けるべき(JOINだけだとINNER JOINになるが、明示的に書く方が良い)
JOIN departments d ON e.department_id = d.department_id
2. テーブルエイリアスは意味のある名前を使用
-- 良い例
FROM employees emp
INNER JOIN departments dept ON emp.department_id = dept.department_id
-- 避けるべき(意味不明)
FROM employees a
INNER JOIN departments b ON a.department_id = b.department_id
3. 複雑なクエリは適切にインデントとフォーマット
SELECT
emp.employee_id,
emp.name,
dept.department_name,
proj.project_name,
CASE
WHEN emp.salary > 800000 THEN 'Senior'
WHEN emp.salary > 500000 THEN 'Mid'
ELSE 'Junior'
END AS level
FROM employees emp
INNER JOIN departments dept
ON emp.department_id = dept.department_id
LEFT JOIN employee_projects ep
ON emp.employee_id = ep.employee_id
LEFT JOIN projects proj
ON ep.project_id = proj.project_id
WHERE emp.status = 'ACTIVE'
AND dept.budget > 1000000
ORDER BY emp.name;
4. WITH句(CTE)を活用
複雑なクエリは共通テーブル式(CTE)で分割する:
WITH active_employees AS (
SELECT employee_id, name, department_id, salary
FROM employees
WHERE status = 'ACTIVE'
),
high_budget_departments AS (
SELECT department_id, department_name
FROM departments
WHERE budget > 1000000
)
SELECT
ae.name,
hbd.department_name,
ae.salary
FROM active_employees ae
INNER JOIN high_budget_departments hbd
ON ae.department_id = hbd.department_id
ORDER BY ae.salary DESC;
実際の移行例
Before(暗黙的JOIN)
SELECT k.sya_id, k.kyoyob08, s.ship_kb
FROM kyomst k, syainjh s, paykojin p
WHERE k.sya_id = s.sya_id
AND k.sya_id = p.sya_id
AND k.sdate <= TO_DATE('2025-08-29', 'YYYY-MM-DD')
AND k.edate >= TO_DATE('2025-08-29', 'YYYY-MM-DD')
AND p.s_key = 'SAMPLE';
After(モダンなSQL)
SELECT
k.sya_id,
k.kyoyob08,
s.ship_kb
FROM kyomst k
INNER JOIN syainjh s ON k.sya_id = s.sya_id
INNER JOIN paykojin p ON k.sya_id = p.sya_id
WHERE k.sdate <= TO_DATE('2025-08-29', 'YYYY-MM-DD')
AND k.edate >= TO_DATE('2025-08-29', 'YYYY-MM-DD')
AND p.s_key = 'SAMPLE'
ORDER BY k.sya_id;
まとめ
モダンなSQLの利点:
- 結合条件とフィルタ条件が明確に分離
- 外部結合も自然に表現可能
- 可読性・メンテナンス性の向上
- 意図しないクロス結合を防げる
- チームでのコードレビューが容易
移行のポイント:
- FROM句の
,
をINNER JOIN ... ON
に変更 - WHERE句の結合条件をON句に移動
- 外部結合が必要な箇所はLEFT/RIGHT JOINを使用
- 適切なフォーマットとエイリアス名を使用