SQL

結合と副問い合わせ

分けて保存したデータを、目的に合う形へ組み合わせましょう。

01

テーブルの関係を確認する

商品一件に対して注文は複数件作れます。これを一対多の関係と呼びます。orders.product_idproducts.idを参照します。

注文を一件追加SQL
INSERT INTO orders (id, product_id, quantity, ordered_at)
VALUES (3, 1, 1, '2026-09-02');

SELECT * FROM orders ORDER BY id;
実行結果OUTPUT
id  product_id  quantity  ordered_at
--  ----------  --------  ----------
1   1           2         2026-09-01
2   2           3         2026-09-02
3   1           1         2026-09-02

商品名を注文テーブルへ毎回保存すると、商品名の変更時に複数行を直す必要があります。識別子で関係付け、必要なときに結合します。

02

INNER JOINで一致する行を結ぶ

内部結合はONの条件が一致する行だけを返します。別名を付けると、どちらのテーブルの列か短く明示できます。

注文と商品を結合SQL
SELECT o.id AS order_id, p.name,
       o.quantity, p.price * o.quantity AS total
FROM orders AS o
INNER JOIN products AS p ON p.id = o.product_id
ORDER BY o.id;
実行結果OUTPUT
order_id  name       quantity  total
--------  ---------  --------  -----
1         SQL入門書  2         5600
2         ノート      3         900
3         SQL入門書  1         2800
結合条件を忘れない 関係のない全組み合わせができると、行数が急増します。実行前に「何と何を同じとして結ぶか」を確認します。
03

LEFT JOINで左側の行を残す

注文のない商品も一覧へ出すには、商品を左側にした外部結合を使います。一致する注文がなければ、注文側の列はNULLになります。

全商品と注文番号SQL
SELECT p.name, o.id AS order_id
FROM products AS p
LEFT JOIN orders AS o ON o.product_id = p.id
ORDER BY p.id, o.id;
実行結果OUTPUT
name        order_id
----------  --------
SQL入門書   1
SQL入門書   3
ノート       2
ボールペン
マグカップ

SQL入門書は注文が2件あるため2行になります。外部結合後にWHERE o.id IS NOT NULLとすると注文なしの商品が消え、実質的に内部結合と同じ結果になる点に注意します。

04

一対多の結果を商品ごとに集計する

商品一行にまとめたい場合は、商品でグループ化します。COUNT(o.id)はNULLを数えないため、注文のない商品は0件になります。

商品別の注文回数と数量SQL
SELECT p.id, p.name,
       COUNT(o.id) AS order_count,
       COALESCE(SUM(o.quantity), 0) AS total_quantity
FROM products AS p
LEFT JOIN orders AS o ON o.product_id = p.id
GROUP BY p.id, p.name
ORDER BY p.id;
実行結果OUTPUT
id  name        order_count  total_quantity
--  ----------  -----------  --------------
1   SQL入門書   2            3
2   ノート       1            3
3   ボールペン   0            0
4   マグカップ   0            0
05

副問い合わせの結果を条件に使う

副問い合わせはSQLの中に置く別の問い合わせです。まず内側で平均価格を求め、その値より高い商品を外側で検索します。

平均より高い商品SQL
SELECT name, price
FROM products
WHERE price > (SELECT AVG(price) FROM products)
ORDER BY price DESC;
実行結果OUTPUT
name       price
---------  -----
SQL入門書  2800

内側が複数行を返す場合は、=ではなくINなど目的に合う演算子が必要です。副問い合わせだけを先に実行し、行数と列を確認すると組み立てやすくなります。

06

EXISTSで関連行の有無を調べる

EXISTSは副問い合わせが一行でも返せば真になります。次は注文されたことがある商品だけを返します。

注文が存在する商品SQL
SELECT p.name
FROM products AS p
WHERE EXISTS (
    SELECT 1
    FROM orders AS o
    WHERE o.product_id = p.id
)
ORDER BY p.id;
実行結果OUTPUT
name
---------
SQL入門書
ノート

NOT EXISTSにすると注文のない商品を探せます。NULLを含む可能性があるNOT INより意図を安全に表せる場合があります。

PRACTICE

ミニ課題:売上金額を集計する

注文のある商品について、商品名と売上金額(価格×注文数量の合計)を大きい順で表示してください。

解答例SQL
SELECT p.name, SUM(p.price * o.quantity) AS sales
FROM products AS p
INNER JOIN orders AS o ON o.product_id = p.id
GROUP BY p.id, p.name
ORDER BY sales DESC, p.id;
実行結果OUTPUT
name       sales
---------  -----
SQL入門書  8400
ノート      900