SQLは「読める」と「速く書ける」が別
SQLの構文を知っていることと、必要なクエリをすぐ書けることは別です。
実務では、正しいSQLをハイスピードで書き、結果を確認し、危険な変更を避ける力が重要です。
SQLの速さは、タイピング速度ではありません。テーブル構造を見て、欲しい結果を分解し、最短で安全なクエリに落とす力です。
まずFROMから考える
SQLは SELECT から書きますが、考える順番は FROM からが楽です。
SELECT users.id, users.name
FROM users
WHERE users.active = true;
考える順番:
1. どのテーブルを見るか
2. どの行に絞るか
3. どの列を返すか
4. 並び順や件数制限は必要か
複雑なSQLでも、この分解は変わりません。
JOINは関係を言葉にする
JOINが苦手な人は、先にテーブル間の関係を言葉にします。
users は orders を複数持つ
orders.user_id は users.id を参照する
SQL:
SELECT
users.id,
users.name,
orders.id AS order_id,
orders.total_amount
FROM users
INNER JOIN orders ON orders.user_id = users.id;
JOINを書く前に、次を確認します。
- 親テーブルはどれか
- 子テーブルはどれか
- 外部キーはどの列か
- 欲しいのは一致する行だけか
- 子がない親も残すか
子がない親も残したいなら LEFT JOIN です。
SELECT users.id, users.name, orders.id AS order_id
FROM users
LEFT JOIN orders ON orders.user_id = users.id;
集計は粒度を先に決める
GROUP BY で大事なのは、何単位で1行にするかです。
ユーザーごとに1行
日付ごとに1行
商品ごとに1行
例: ユーザーごとの注文数
SELECT
users.id,
users.name,
COUNT(orders.id) AS order_count
FROM users
LEFT JOIN orders ON orders.user_id = users.id
GROUP BY users.id, users.name
ORDER BY order_count DESC;
集計SQLを書くときは、先に出力イメージを作ります。
| user_id | name | order_count |
|---|---|---|
| 1 | Ada | 3 |
| 2 | Ken | 0 |
出力の1行が何を表すかを決めると、GROUP BY すべき列が見えます。
WHEREとHAVINGを分ける
WHERE は集計前の行を絞ります。HAVING は集計後のグループを絞ります。
SELECT user_id, COUNT(*) AS order_count
FROM orders
WHERE status = 'paid'
GROUP BY user_id
HAVING COUNT(*) >= 3;
読み方:
paidの注文だけに絞る
user_idごとに集計する
注文数が3以上のユーザーだけ残す
この違いを理解すると、集計SQLのミスが減ります。
更新系SQLはSELECTから始める
UPDATE や DELETE は、必ず対象確認から始めます。
SELECT id, email, active
FROM users
WHERE last_login_at < now() - interval '1 year'
AND active = true;
対象が正しいと確認してから更新します。
BEGIN;
UPDATE users
SET active = false
WHERE last_login_at < now() - interval '1 year'
AND active = true;
-- 件数確認
COMMIT;
危険なSQLほど、トランザクションと件数確認を使います。
クエリ品質のチェック
SQLを書いたら、次を確認します。
| 観点 | 確認 |
|---|---|
| 正確性 | 期待した行だけ返るか |
| NULL | NULL を取りこぼしていないか |
| 重複 | JOINで行が増えすぎていないか |
| 件数 | 想定件数と合うか |
| 並び順 | ORDER BY が必要か |
| 速度 | データ量が増えても耐えるか |
| 安全性 | 更新・削除の影響範囲は確認したか |
SQLは「動いた」だけでは不十分です。結果が正しいか、件数が妥当か、遅くならないかを見ます。
よくある実務ミス
| ミス | 起きること |
|---|---|
| JOIN条件が足りない | 行が爆発的に増える |
LEFT JOIN 後にWHEREで右テーブルを絞る | 実質INNER JOINになる |
COUNT(*) と COUNT(column) を混同 | NULLの扱いを間違える |
ORDER BY なしで最新1件を取る | 結果が不安定 |
| 更新前にSELECTしない | 大量更新事故 |
| 本番サイズで見ない | データ増加後に遅くなる |
速く書くほど、確認の型が必要です。
まとめ
SQL力は、構文を知っているだけでは足りません。
FROMから考える- JOINは関係を言葉にする
- 集計は1行の粒度を先に決める
WHEREとHAVINGを分ける- 更新系SQLはSELECTで確認してから実行する
- 正確性、件数、速度、安全性を見る
正しいSQLを速く書けるようになると、アプリ側の実装もシンプルになります。