導入
内部結合(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;