データベース操作で欠かせないのが「結合(JOIN)」と「副問い合わせ(サブクエリ)」です。
どちらも複数のテーブルを扱う際に使われる機能ですが、役割や使いどころが異なります。
たとえば、売上データと顧客情報を結びつけたいときには「結合」を使います。
一方で、「特定条件を満たすデータだけを別のテーブルに使いたい」場合は、副問い合わせが活躍します。
この記事では、まず結合と副問い合わせの基本をわかりやすく解説し、その後「結合と副問い合わせを同時に使う」実践的なケースを具体的なSQL例とともに紹介します。
初心者から中級者まで、業務で使える実践知識が身につく内容です。
SQLの結合とは?基本を理解しよう
SQLの「結合(JOIN)」とは、複数のテーブルを共通するキー(列)で結びつけて1つの結果セットとして取得する機能です。
たとえば、次のような2つのテーブルがあるとします。
顧客テーブル(customers)
customer_id | name | city |
---|---|---|
1 | 田中太郎 | 東京 |
2 | 鈴木花子 | 大阪 |
3 | 佐藤健 | 福岡 |
注文テーブル(orders)
order_id | customer_id | order_date | amount |
---|---|---|---|
101 | 1 | 2025-10-01 | 5000 |
102 | 2 | 2025-10-02 | 8000 |
103 | 1 | 2025-10-03 | 12000 |
顧客名と注文金額を同時に表示したい場合、customer_id
をキーにして結合します。
SELECT
customers.name,
orders.order_date,
orders.amount
FROM
customers
INNER JOIN orders
ON customers.customer_id = orders.customer_id;
このSQLでは、customers
とorders
を「内部結合(INNER JOIN)」しており、
結果は以下のようになります。
name | order_date | amount |
---|---|---|
田中太郎 | 2025-10-01 | 5000 |
鈴木花子 | 2025-10-02 | 8000 |
田中太郎 | 2025-10-03 | 12000 |
結合の主な種類は以下の3つです。
- INNER JOIN:両方のテーブルに存在するデータのみを取得
- LEFT JOIN:左側テーブルのすべてのデータを取得し、右側が一致しない場合はNULL
- RIGHT JOIN:右側テーブルのすべてのデータを取得(LEFTの逆)
副問い合わせ(サブクエリ)とは?基本の考え方
副問い合わせとは、SQL文の中で別のSQL文を入れ子にして使う構文のことです。
たとえば、注文テーブルから「平均金額より高い注文」を抽出したい場合、
次のように書けます。
SELECT *
FROM orders
WHERE amount > (
SELECT AVG(amount)
FROM orders
);
ここで括弧内の SELECT AVG(amount)
が副問い合わせです。
副問い合わせは一時的に別の計算結果を得るために使われ、メインのSELECT文の条件として利用できます。
副問い合わせの種類は大きく3つに分かれます。
- スカラ副問い合わせ:1つの値を返す(上の例がこれ)
- 行副問い合わせ:1行のデータを返す
- テーブル副問い合わせ:複数行を返す(FROM句で使用)
結合と副問い合わせの違い
項目 | 結合(JOIN) | 副問い合わせ(サブクエリ) |
---|---|---|
処理対象 | 複数テーブルを結びつける | 一時的な結果を他のクエリで利用する |
可読性 | 複雑になると見づらい | 単純な条件なら見やすい |
実行速度 | 高速(インデックスを使える) | 条件によっては遅くなる |
主な用途 | テーブルの結合表示 | 条件付きの絞り込み、計算結果の利用 |
結論としては、
「関連データを横に並べたいときは結合」、
「条件や集計結果を条件として使いたいときは副問い合わせ」です。
結合と副問い合わせを同時に使う状況とは?
実際の業務では、結合と副問い合わせを「組み合わせて」使う場面も多くあります。
代表的なケースは次のようなものです。
- 結合したデータに対して、さらに別の条件を副問い合わせで絞り込みたいとき
- 特定の集計値(例:平均、最大値)を条件に結合結果を制御したいとき
- 他のテーブルの存在確認を副問い合わせで行いたいとき
例文①:平均金額より高い注文を顧客名付きで表示
まず、すべての注文の平均金額を副問い合わせで求め、
その結果をもとに、JOINで顧客名を結合します。
SELECT
c.name,
o.order_date,
o.amount
FROM
customers c
INNER JOIN orders o
ON c.customer_id = o.customer_id
WHERE
o.amount > (
SELECT AVG(amount)
FROM orders
);
このSQLの流れを言葉で説明すると、
- 副問い合わせ
(SELECT AVG(amount) FROM orders)
で全体の平均金額を計算 - その結果を使って、メインクエリで平均より高い注文を抽出
- 抽出結果を
customers
テーブルと結合して顧客名を取得
結果は、平均金額を上回る顧客と注文が一覧で表示されます。
例文②:特定の都市に住む顧客の注文履歴を取得
次に、顧客テーブルから「東京に住む顧客」のIDだけを副問い合わせで抽出し、
そのIDを条件に orders
テーブルと結合して注文履歴を表示します。
SELECT
o.order_id,
c.name,
o.order_date,
o.amount
FROM
orders o
INNER JOIN customers c
ON o.customer_id = c.customer_id
WHERE
c.customer_id IN (
SELECT customer_id
FROM customers
WHERE city = '東京'
);
このように、
「副問い合わせで特定条件に合う顧客IDを取得 → 結合で詳細を表示」
という流れを組むことで、柔軟なデータ抽出が可能になります。
例文③:最新注文のみを結合して顧客情報を表示
もう少し発展的な例です。
顧客ごとに「最新の注文」を1件だけ表示したいとき、
副問い合わせを利用して「最新日付の注文ID」を抽出し、
その結果をJOINで結びます。
SELECT
c.name,
o.order_date,
o.amount
FROM
customers c
INNER JOIN orders o
ON c.customer_id = o.customer_id
WHERE
o.order_date = (
SELECT MAX(order_date)
FROM orders
WHERE customer_id = c.customer_id
);
ここでのポイントは、副問い合わせ内で「外側のテーブル(customers)」を参照している点。
このような構文を**相関サブクエリ(correlated subquery)**と呼びます。
相関サブクエリは、1件ずつ比較・抽出するため処理は重くなりがちですが、
「1件だけ取得したい」など限定的な用途では非常に便利です。
実務での使い分けのコツ
- 結合で済む場合は結合を使う(副問い合わせは処理コストが高い)
- 副問い合わせは条件式で使うと読みやすい
- 相関サブクエリを多用すると遅くなるため、ビュー化や一時テーブル化も検討する
- SELECT句内の副問い合わせで集計を出すのも有効
実際のSQLチューニングでは、
「結合 → GROUP BY → HAVING」の流れと「副問い合わせを組み合わせる」ことで、
柔軟かつ効率的なデータ抽出が可能になります。
まとめ
SQLの結合と副問い合わせは、それぞれ単体でも強力ですが、
組み合わせることでより柔軟なデータ取得が実現します。
- 結合:テーブルを横方向に結びつける
- 副問い合わせ:条件や集計を補助的に利用する
- 両方を組み合わせる:条件付き結合や最新データ抽出など、実務的な処理が可能
実際の業務では「結合+副問い合わせ」を使う場面は多く、
販売管理、会員データ分析、在庫管理などで頻繁に登場します。
ぜひこの記事の例文を実際に実行して、
「SQLがデータを自在に操るツール」であることを実感してみてください。