コース一覧
SQL実践:JOIN・サブクエリ・データ更新
LEFT/RIGHT OUTER JOIN

SQL実践:JOIN・サブクエリ・データ更新

JOIN、集合演算、サブクエリ、CTE、DDL・DMLを学び、複数テーブルを組み合わせてデータベースを作成・更新する無料コースです。

1
テーブル結合
01. なぜ結合が必要か5分
02. INNER JOINの基本5分
03. LEFT/RIGHT OUTER JOIN5分
04. 複数テーブルの結合5分
05. 自己結合5分
06. 集合演算 UNION/INTERSECT/EXCEPT5分
07. 結合の実践演習5分
08. テーブル結合クイズ5分
2
サブクエリ活用
01. サブクエリとは5分
02. WHERE句のサブクエリ5分
03. FROM句のサブクエリ5分
04. SELECT句のサブクエリ5分
05. WITH句(CTE)の活用5分
06. サブクエリ実践クイズ5分
3
テーブル作成とデータ操作
01. CREATE DATABASE と CREATE TABLE5分
02. データ型の選び方5分
03. INSERT 文でデータを追加する5分
04. UPDATE 文でデータを更新する5分
05. DELETE 文でデータを削除する5分
06. 物理削除と論理削除5分
07. ALTER TABLE で構造を変更する5分
08. 制約 (NOT NULL / UNIQUE / DEFAULT)5分
09. TRUNCATE と DROP5分
10. DDL / DML 実践クイズ5分

LEFT/RIGHT OUTER JOIN

全商品のレビュー状況を一覧にしてほしい、と頼まれたとします。内部結合で書くと、レビューがまだ 1 件も付いていない本が一覧から消えます。本当に知りたかったのは、その消えたほうだったりします。

左のテーブルを丸ごと残す

SQL クエリ

SELECT b.title, r.rating
FROM books b
LEFT JOIN reviews r
  ON b.id = r.book_id;

LEFT JOIN は FROM に書いた左のテーブルの行を全部残します。右に相手が見つからなかった行は、右側の列が NULL で埋まります。OUTER は省略でき、LEFT OUTER JOIN と LEFT JOIN は同じものです。

RIGHT JOIN は左右が入れ替わるだけです。実務では主軸のテーブルを左に置いて LEFT JOIN で広げる形に統一するのが読みやすく、RIGHT JOIN が混ざったクエリはレビューで指摘されがちです。

空欄と 0 は、読み手にとって別のもの

SQL クエリ

-- レビューが無い本の avg_rating は NULL になる
SELECT b.title, AVG(r.rating) AS avg_rating
FROM books b
LEFT JOIN reviews r ON b.id = r.book_id
GROUP BY b.id, b.title;

集計の対象になる行が 1 つも無いと、AVG も SUM も 0 ではなく NULL を返します。レポートに空欄が並ぶと、集計漏れなのか本当に 0 なのかが読み手に伝わりません。COALESCE(AVG(r.rating), 0) のように包んで 0 に置き換えておくと、意図がはっきりします。

同じ理由で、件数の数え方にも注意が要ります。COUNT(*) は行そのものを数えるので、右が NULL で埋まっただけの行も 1 件として数えます。レビューが 0 件の本が「1 件」と出てしまうわけです。右のテーブルの列を指定して COUNT(r.id) と書けば、NULL は数えられず 0 になります。

WHERE に右の列を書くと、外部結合が無かったことになる

SQL クエリ

-- レビューが 1 件も付いていない本を探す
SELECT b.title
FROM books b
LEFT JOIN reviews r ON b.id = r.book_id
WHERE r.id IS NULL;

これは意図どおりに動きます。右が空だった行を狙って拾っているからです。一方で WHERE r.rating >= 4 のような普通の条件を右の列に書くと、右側が NULL の行は条件に合わずに全部落ちます。結果は内部結合とまったく同じになり、LEFT JOIN と書いた意味が消えます。

左を全部残したまま右に条件を付けたいときは、その条件を ON 句の側へ移します。

解説

LEFT JOIN に WHERE を足したら、件数をもう一度見てください。左の全件が保たれているかどうかは、そこでしか分かりません。

テーブル構造

CREATE TABLE customers (
  id INT PRIMARY KEY,
  name VARCHAR(30)
);

CREATE TABLE orders (
  id INT PRIMARY KEY,
  customer_id INT,
  amount INT
);

INSERT INTO customers VALUES
  (1, '田中'),
  (2, '鈴木'),
  (3, '佐藤'),
  (4, '高橋'),
  (5, '山田');

INSERT INTO orders VALUES
  (1001, 1, 2000),
  (1002, 1, 3000),
  (1003, 3, 1500),
  (1004, 4, 5000),
  (1005, 4, 2500);

期待される出力

customer_idcustomer_nametotal_amount
1田中5000
2鈴木0
3佐藤1500
4高橋7500
5山田0

ヒント

LEFT JOIN を使うと右側にレコードがなくても左テーブル (customers) は全件残る

未購入顧客は SUM が NULL になるので COALESCE(SUM(...), 0) で 0 にする

GROUP BY は c.id と c.name 両方を含める

このレッスンに出てくる用語

意味があいまいなまま進んだ語は、ここから読み直せます。

  • レビューコードを読み合い品質を上げる工程
  • ビュークエリに名前をつけて再利用する仮想表
  • テーブルDB の表 (Excel のシートみたいなもの)
query.sql
学習モード
エディタを読み込んでいます
コードの実行結果
データベースを初期化中...