本文へスキップ
BecomeCoder

SQL データ操作 (DML)コース · 第3章 テーブルをつなぐ · レッスン11

JOIN の連鎖 ― 3つ以上の表をつなぐ

ブラウザで完結

導入

「誰が・何を・いくつ買ったか」を一覧したい。ところがこの情報は、1つの表には入っていません。会員名は users、商品名は products、個数は order_items、その紐付けは orders4つの表にまたがっています正規化された DB では、こうして JOIN を数珠つなぎにして情報を組み立てます。

説明

JOIN は、ON を足しながら何個でもつなげられます。関係の鎖にそって「明細 → 注文 → 会員」「明細 → 商品」とたどります。

flowchart LR
    OI["order_items<br/>(誰が何をいくつ、の“いくつ”)"]
    O["orders<br/>(注文=会員との橋渡し)"]
    U["users<br/>(会員名)"]
    P["products<br/>(商品名・価格)"]
    OI -->|"oi.order_id = o.id"| O
    O -->|"o.user_id = u.id"| U
    OI -->|"oi.product_id = p.id"| P
SELECT u.name AS 会員, p.name AS 商品, oi.quantity AS 個数
FROM order_items AS oi
JOIN orders   AS o ON oi.order_id   = o.id
JOIN users    AS u ON o.user_id     = u.id
JOIN products AS p ON oi.product_id = p.id;

ここまで来ると、実務でよくある「売上の集計」も書けます。金額は「個数 × 単価」なので、order_items.quantityproducts.price を掛けて SUM します。「会員ごとの購入金額合計」はこうです。

SELECT u.name AS 会員, SUM(oi.quantity * p.price) AS 購入金額
FROM order_items AS oi
JOIN orders   AS o ON oi.order_id   = o.id
JOIN users    AS u ON o.user_id     = u.id
JOIN products AS p ON oi.product_id = p.id
GROUP BY u.name
ORDER BY 購入金額 DESC;

金額を各注文の行にコピーして持たず、必要なときに掛け算で導く――これが正規化された設計の実力です。単価が変わっても、products を1か所直すだけで、過去も含めた計算がやり直せます。

やってみよう

初期表示のクエリを実行し、「会員・商品・個数」が1つの表に組み上がることを確認しましょう。次に上の「購入金額」クエリを実行し、正規化されたバラバラの表から売上ランキングが作れることを体感してください。

演習

上と同じ4表の JOIN を使って、商品ごと(p.name)の販売個数合計を、多い順に取り出してください(SUM(oi.quantity) を使います)。

ヒント1を見る

GROUP BY p.name でまとめ、SUM(oi.quantity) を集計します。並べ替えは ORDER BY ... DESC

ヒント2を見る

SELECT p.name, SUM(oi.quantity) AS 個数 FROM order_items AS oi JOIN products AS p ON oi.product_id = p.id GROUP BY p.name ORDER BY 個数 DESC;

実際に動かしてみよう

下のエディタにクエリを書いて「実行」を押すと、ブラウザ内のSQLiteで結果が表示されます。本文の例をそのまま試したり、書き換えたりしてみましょう。

SQL — ブラウザ内で実行(SQLite)

ブラウザ内でSQLを動かす環境(SQLite)を読み込みます(初回のみ一瞬)。
スクロールして表示された時点でも自動で読み込まれます。