本文へスキップ
BecomeCoder

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

LEFT JOIN ― 相手がいない行も残す

ブラウザで完結

導入

内部結合JOIN)は「両方に一致がある行だけ」を返しました。でも実務では、「一度も注文していない会員も含めて、会員全員を出したい」ことがあります。片方の表を丸ごと残すのが LEFT JOIN(左外部結合)です。

説明

LEFT JOIN は、「左の表(FROM の直後に書いた表)の行は全部残す。右の表に相手がいなければ、その列は NULL」という結合です。

flowchart LR
    subgraph U["users(左=全部残す)"]
        U6["山本(注文なし)"]
        U1["佐藤(注文あり)"]
    end
    subgraph O["orders(右)"]
        O1["佐藤の注文"]
    end
    U1 -->|"一致あり"| O1
    U6 -->|"相手なし → NULL"| N["orders 側は NULL のまま残る"]
SELECT u.name, o.id AS order_id
FROM users AS u
LEFT JOIN orders AS o ON o.user_id = u.id;

注文のない会員(山本さん)も、order_id が NULL の行として出てきます。もし普通の JOIN(内部結合)で書いていたら、山本さんは消えてしまいます。「全員を出したいのか、一致した人だけでいいのか」で使い分けます。

LEFT JOIN は「まだ何もしていない人」を探すのに便利です。集計と組み合わせて「注文が0件の会員」を出すには、こう書きます。

SELECT u.name, COUNT(o.id) AS 注文数
FROM users AS u
LEFT JOIN orders AS o ON o.user_id = u.id
GROUP BY u.name
HAVING COUNT(o.id) = 0;

ここで COUNT(*) ではなく COUNT(o.id) を使うのがコツです。COUNT(*) は「NULL の行も1行」と数えてしまいますが、COUNT(o.id) は NULL を数えないので、注文のない会員が正しく「0」になります。

やってみよう

初期表示の LEFT JOIN を実行し、注文のない山本さんが NULL 付きで残ることを確認しましょう。次に LEFT JOIN を普通の JOIN に変えて実行し、山本さんが消えることを見比べてください。この差が、内部結合と外部結合の違いです。

演習

LEFT JOIN を使って、会員ごとの注文件数を(注文0件の会員も含めて)取り出してください。u.name と件数を並べます。

ヒント1を見る

users を左、orders を右にして LEFT JOIN。件数は COUNT(o.id)GROUP BY u.name

ヒント2を見る

SELECT u.name, COUNT(o.id) AS 注文数 FROM users AS u LEFT JOIN orders AS o ON o.user_id = u.id GROUP BY u.name;

実際に動かしてみよう

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

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

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