🔥
# 【SQL】SELECT * と INNER JOIN で起きる duplicate column name エラーの解決法
はじめに
SQLのJOIN操作で「手軽に全カラム取得したい」と思ってSELECT *を使ったら、予期しないエラーに遭遇したことはありませんか?
今回はSELECT *とINNER JOINを組み合わせる際のUSING句とON句の使い分けについて、実際に発生し得るエラーと解決策を解説します。
🚨 問題のあるSQL
以下のSQLは僕が書いた
-- ❌ 重複列が発生しやすいパターン(ON + SELECT *)
SELECT *
FROM users u
INNER JOIN orders o ON u.user_id = o.user_id;
一見問題なさそうに見えますが、実際には同名カラムが結果セットに並ぶため、これをビュー化したり、ORM/BIツールに流したりすると:
Error: duplicate column name 'user_id'
といったエラーの原因になります(DBやツールによっては、SELECT単体は通ってもスキーマ化で落ちます)。
✅ 解決策
1. USING句を使用する(対応DBなら推奨)
-- ✅ SELECT * を使いたいなら USING が安全(MySQL / PostgreSQL / SQLite)
SELECT *
FROM users u
INNER JOIN orders o USING (user_id);
ポイント:
- 結合キーが1列に統合されるため、
SELECT *でも重複列名にならない - 記述が簡潔で読みやすい
2. カラムを明示的に指定(最推奨)
-- ✅ 必要なカラムのみ明示(DB/ツールに最も優しい)
SELECT
u.user_id,
u.name,
u.email,
o.order_id,
o.amount
FROM users u
INNER JOIN orders o ON u.user_id = o.user_id;
ポイント:
- 転送量削減・スキーマ変化耐性・可観測性の観点でもベスト
- ビュー化やAPI公開を見据えた"壊れにくい"SELECT
3. テーブル指定でSELECT * + 別名付け
-- ✅ table.* と必要列だけを組み合わせ、衝突する列は別名にする
SELECT
u.*,
o.order_id,
o.amount,
o.user_id AS order_user_id -- ← 衝突するなら別名で回避
FROM users u
INNER JOIN orders o ON u.user_id = o.user_id;
ポイント:
- どうしても*を使いたい場合の妥協案
- ビュー化や外部公開前に"列名一意"を必ず担保
🔍 エラーの原因
USING句の特性
USING句は結合条件を簡潔に書けて便利で、以下の特性があります:
- 両テーブルの結合カラムを自動的に1列へ"統合"
- テーブル名(エイリアス)の指定が不要
- 結果セットには統合されたカラムが1つだけ含まれる
SELECT * と ON句の組み合わせ問題
-- テーブル構造例
users: user_id, name, email
orders: order_id, user_id, amount
-- ON句 + SELECT * の実行時
SELECT *
FROM users u
INNER JOIN orders o ON u.user_id = o.user_id;
この場合、SQLエンジンは以下の処理を行います:
-
u.user_idとo.user_idを比較して結合 -
SELECT *で全カラムを取得 u.user_idとo.user_idの"同名カラムが両方とも残る"- 結果セット自体は許容されても、ビュー作成や一部ツールが"duplicate column name"でエラー
対してUSING (user_id)を用いると結合キーは1列に統合され、SELECT *でも同名カラムの衝突が起きません(※SQL ServerはUSING非対応)。
📚 詳細解説
USING vs ON の使い分け
| 項目 | USING句 | ON句 |
|---|---|---|
| 記述の簡潔性 | ◎ | △ |
| SELECT * との相性 | ◎ | × |
| 複雑な条件 | △ | ◎ |
| 可読性 | ◎(結合キーが明確) | ◎(柔軟だが冗長になりがち) |
| 重複カラム回避 | ◎(統合) | ×(両方残る) |
補足:SQL Server は USING 非対応のため、常に ON を使います。その際は列の明示・別名付けが実務上の必須テクニックです。
💡 覚えておくべきポイント
黄金ルール
SELECT *を使うならUSINGを優先(対応DBのみ)。
ONを使うときは"必要な列だけ明示"し、衝突列には必ず別名を付ける。
ビュー化・外部公開前に"列名の一意性"を必ず確認。
なぜこの方針が安全なのか
- 列名一意性: ツール連携・ビュー作成でコケない
- 拡張性: 複雑条件は ON、それ以外は USING でシンプルに
- 可読性/保守性: 明示的な列リストはレビューと差分追跡に強い
- パフォーマンス: 過剰データ転送を防ぎ、計測も容易
まとめ
-
USING句は結合キーを統合するため、SELECT *との相性が良い(MySQL / PostgreSQL / SQLite) -
ON句は同名カラムが両方残るため、SELECT *だと duplicate column name の原因になりやすい(特にビュー作成やツール連携時) - 最も確実なのは"列を明示"し、衝突し得る列には別名を付けること
- SQL Server は USING が使えないため、明示列 + 別名付けが必須の作法
SQLの結合は基本機能ですが、列名の一意性を意識しておくだけで、運用・連携時のトラブルを大幅に減らせます。エラーに遭遇したら、まずJOIN方法と列名を見直しましょう。
Discussion