データベース操作で欠かせないのが「結合(JOIN)」と「副問い合わせ(サブクエリ)」です。
どちらも複数のテーブルを扱う際に使われる機能ですが、役割や使いどころが異なります。
たとえば、売上データと顧客情報を結びつけたいときには「結合」を使います。
一方で、「特定条件を満たすデータだけを別のテーブルに使いたい」場合は、副問い合わせが活躍します。
この記事では、まず結合と副問い合わせの基本をわかりやすく解説し、その後「結合と副問い合わせを同時に使う」実践的なケースを具体的なSQL例とともに紹介します。
初心者から中級者まで、業務で使える実践知識が身につく内容です。
SQLの「結合(JOIN)」とは、複数のテーブルを共通するキー(列)で結びつけて1つの結果セットとして取得する機能です。
たとえば、次のような2つのテーブルがあるとします。
| customer_id | name | city |
|---|---|---|
| 1 | 田中太郎 | 東京 |
| 2 | 鈴木花子 | 大阪 |
| 3 | 佐藤健 | 福岡 |
| 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つです。
副問い合わせとは、SQL文の中で別のSQL文を入れ子にして使う構文のことです。
たとえば、注文テーブルから「平均金額より高い注文」を抽出したい場合、
次のように書けます。
SELECT *
FROM orders
WHERE amount > (
SELECT AVG(amount)
FROM orders
);
ここで括弧内の SELECT AVG(amount) が副問い合わせです。
副問い合わせは一時的に別の計算結果を得るために使われ、メインのSELECT文の条件として利用できます。
副問い合わせの種類は大きく3つに分かれます。
| 項目 | 結合(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件だけ取得したい」など限定的な用途では非常に便利です。
実際のSQLチューニングでは、
「結合 → GROUP BY → HAVING」の流れと「副問い合わせを組み合わせる」ことで、
柔軟かつ効率的なデータ抽出が可能になります。
SQLの結合と副問い合わせは、それぞれ単体でも強力ですが、
組み合わせることでより柔軟なデータ取得が実現します。
実際の業務では「結合+副問い合わせ」を使う場面は多く、
販売管理、会員データ分析、在庫管理などで頻繁に登場します。
ぜひこの記事の例文を実際に実行して、
「SQLがデータを自在に操るツール」であることを実感してみてください。