この章で得られるスキル:
✅ JOINの必要性を説明できる
✅ INNER JOINで2つのテーブルを結合できる
✅ LEFT OUTER JOINで外部結合ができる
✅ 自己結合ができる
✅ 3つ以上のテーブルを結合できる
✅ JOINとWHERE、GROUP BYを組み合わせられる
Step 0: まず体験してみよう
シナリオ:社員の名前と部門名を一緒に表示したい
前章で学んだ通り、テーブルは正規化によって分割されている。
社員テーブルには 部門ID しかなく、 部門名 は部門テーブルにある。
社員の名前と部門名を一緒に表示するにはどうすればよいか?
CREATE TABLE departments (
dept_id INTEGER PRIMARY KEY,
dept_name VARCHAR(50) NOT NULL UNIQUE,
location VARCHAR(50)
);
CREATE TABLE employees (
emp_id INTEGER PRIMARY KEY,
emp_name VARCHAR(50) NOT NULL,
dept_id INTEGER REFERENCES departments(dept_id),
hire_date DATE NOT NULL,
salary INTEGER CHECK (salary > 0),
email VARCHAR(100) UNIQUE
);
INSERT INTO departments VALUES (1, '営業部', '東京');
INSERT INTO departments VALUES (2, '開発部', '大阪');
INSERT INTO departments VALUES (3, '人事部', '東京');
INSERT INTO departments VALUES (4, '広報部', '福岡');
INSERT INTO employees VALUES (1, '田中太郎', 1, '2020-04-01', 350000, 'tanaka@example.com');
INSERT INTO employees VALUES (2, '佐藤花子', 2, '2021-04-01', 400000, 'sato@example.com');
INSERT INTO employees VALUES (3, '鈴木一郎', 2, '2022-04-01', 320000, 'suzuki@example.com');
INSERT INTO employees VALUES (4, '高橋美咲', 3, '2023-04-01', 280000, 'takahashi@example.com');
INSERT INTO employees VALUES (5, '伊藤健太', 1, '2021-10-01', 330000, 'ito@example.com');
INSERT INTO employees VALUES (6, '渡辺あかり', NULL, '2024-01-15', 300000, 'watanabe@example.com');
-- 社員テーブルだけでは部門名がわからない
SELECT emp_name, dept_id FROM employees;
-- JOINで部門名も一緒に表示できる!
SELECT e.emp_name, d.dept_name
FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id;
JOIN を使うと、分割されたテーブルを結合して必要な情報をまとめて取得できる。
正規化でテーブルを分割するから、JOINで結合する必要がある。
「分割」と「結合」はセットで理解しよう。
Step 1: JOINの基本概念
なぜJOINが必要か
正規化によってテーブルを分割すると、関連するデータが複数のテーブルに散らばる。
社員テーブルの dept_id が、部門テーブルの dept_id への 外部キー になっている。
この外部キーが、テーブル結合の 橋渡し をする。
JOINの種類
種類 説明 結果 INNER JOIN 両方のテーブルに一致するデータだけ取得 一致しないデータは除外 LEFT OUTER JOIN 左側テーブルの全データ + 一致する右側データ 一致しない右側はNULL RIGHT OUTER JOIN 右側テーブルの全データ + 一致する左側データ 一致しない左側はNULL CROSS JOIN 全ての組み合わせ(直積) めったに使わない
実務で最も使うのは INNER JOIN と LEFT OUTER JOIN である。
Step 2: INNER JOIN(内部結合)
基本構文
SELECT 列名 FROM テーブル 1 INNER JOIN テーブル 2 ON テーブル 1. 列名 = テーブル 2. 列名 ;
ON句 で結合条件を指定する。通常は外部キーと主キーの一致を条件にする。
CREATE TABLE departments (
dept_id INTEGER PRIMARY KEY,
dept_name VARCHAR(50) NOT NULL UNIQUE,
location VARCHAR(50)
);
CREATE TABLE employees (
emp_id INTEGER PRIMARY KEY,
emp_name VARCHAR(50) NOT NULL,
dept_id INTEGER REFERENCES departments(dept_id),
hire_date DATE NOT NULL,
salary INTEGER CHECK (salary > 0),
email VARCHAR(100) UNIQUE
);
INSERT INTO departments VALUES (1, '営業部', '東京');
INSERT INTO departments VALUES (2, '開発部', '大阪');
INSERT INTO departments VALUES (3, '人事部', '東京');
INSERT INTO departments VALUES (4, '広報部', '福岡');
INSERT INTO employees VALUES (1, '田中太郎', 1, '2020-04-01', 350000, 'tanaka@example.com');
INSERT INTO employees VALUES (2, '佐藤花子', 2, '2021-04-01', 400000, 'sato@example.com');
INSERT INTO employees VALUES (3, '鈴木一郎', 2, '2022-04-01', 320000, 'suzuki@example.com');
INSERT INTO employees VALUES (4, '高橋美咲', 3, '2023-04-01', 280000, 'takahashi@example.com');
INSERT INTO employees VALUES (5, '伊藤健太', 1, '2021-10-01', 330000, 'ito@example.com');
INSERT INTO employees VALUES (6, '渡辺あかり', NULL, '2024-01-15', 300000, 'watanabe@example.com');
-- INNER JOIN:社員名と部門名を結合
SELECT e.emp_name, d.dept_name, d.location
FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id;
INNER JOINの特徴
結果を確認すると、 渡辺あかり (dept_id が NULL)と 広報部 (社員がいない)は表示されない。
INNER JOINは 両方のテーブルに一致するデータだけ を返すためである。
上のコードのSELECT文を変更して、 e.salary も表示してみよう。
Step 3: テーブルの別名(エイリアス)
なぜ別名が必要か
JOINでは複数のテーブルに同じ名前の列がある場合がある。例えば、どちらのテーブルの dept_id かを明確にする必要がある。
SELECT employees . emp_name , departments . dept_name FROM employees INNER JOIN departments ON employees . dept_id = departments . dept_id ; SELECT e . emp_name , d . dept_name FROM employees e INNER JOIN departments d ON e . dept_id = d . dept_id ;
別名の付け方
書き方 例 テーブル名 AS 別名employees AS eテーブル名 別名employees e
AS は省略可能である。実務ではどちらも使われるが、短い別名を使うのが一般的である。
別名を付けたら、そのクエリ内ではテーブル名の代わりに別名を使う。
FROM employees e と書いた後で employees.emp_name と書くとエラーになる場合がある。
Step 4: LEFT OUTER JOIN(左外部結合)
INNER JOINでは取りこぼすデータがある
Step 2で見たように、INNER JOINは 一致しないデータを除外 する。
部門に所属していない社員や、社員のいない部門が結果に含まれない。
全社員を表示しつつ、部門名がわかる社員は部門名も表示したい という場合は LEFT OUTER JOIN を使う。
CREATE TABLE departments (
dept_id INTEGER PRIMARY KEY,
dept_name VARCHAR(50) NOT NULL UNIQUE,
location VARCHAR(50)
);
CREATE TABLE employees (
emp_id INTEGER PRIMARY KEY,
emp_name VARCHAR(50) NOT NULL,
dept_id INTEGER REFERENCES departments(dept_id),
hire_date DATE NOT NULL,
salary INTEGER CHECK (salary > 0),
email VARCHAR(100) UNIQUE
);
INSERT INTO departments VALUES (1, '営業部', '東京');
INSERT INTO departments VALUES (2, '開発部', '大阪');
INSERT INTO departments VALUES (3, '人事部', '東京');
INSERT INTO departments VALUES (4, '広報部', '福岡');
INSERT INTO employees VALUES (1, '田中太郎', 1, '2020-04-01', 350000, 'tanaka@example.com');
INSERT INTO employees VALUES (2, '佐藤花子', 2, '2021-04-01', 400000, 'sato@example.com');
INSERT INTO employees VALUES (3, '鈴木一郎', 2, '2022-04-01', 320000, 'suzuki@example.com');
INSERT INTO employees VALUES (4, '高橋美咲', 3, '2023-04-01', 280000, 'takahashi@example.com');
INSERT INTO employees VALUES (5, '伊藤健太', 1, '2021-10-01', 330000, 'ito@example.com');
INSERT INTO employees VALUES (6, '渡辺あかり', NULL, '2024-01-15', 300000, 'watanabe@example.com');
-- INNER JOIN:部門未所属の渡辺あかりが表示されない
SELECT e.emp_name, d.dept_name
FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id;
-- LEFT JOIN:全社員が表示される(部門名がない場合はNULL)
SELECT e.emp_name, d.dept_name
FROM employees e
LEFT OUTER JOIN departments d ON e.dept_id = d.dept_id;
INNER JOIN と LEFT JOIN の比較
結合方法 渡辺あかり(部門なし) 広報部(社員なし) INNER JOIN ❌ 表示されない ❌ 表示されない LEFT JOIN(employees が左) ✅ 部門名はNULL ❌ 表示されない LEFT JOIN(departments が左) ❌ 表示されない ✅ 社員名はNULL
LEFT OUTER JOIN は LEFT JOIN と省略して書ける。実務ではこの省略形の方がよく使われる。
NULLを使って「一致しないデータ」を見つける
LEFT JOINとIS NULLを組み合わせると、 どの部門にも所属していない社員 を見つけられる。
CREATE TABLE departments (
dept_id INTEGER PRIMARY KEY,
dept_name VARCHAR(50) NOT NULL UNIQUE,
location VARCHAR(50)
);
CREATE TABLE employees (
emp_id INTEGER PRIMARY KEY,
emp_name VARCHAR(50) NOT NULL,
dept_id INTEGER REFERENCES departments(dept_id),
hire_date DATE NOT NULL,
salary INTEGER CHECK (salary > 0),
email VARCHAR(100) UNIQUE
);
INSERT INTO departments VALUES (1, '営業部', '東京');
INSERT INTO departments VALUES (2, '開発部', '大阪');
INSERT INTO departments VALUES (3, '人事部', '東京');
INSERT INTO departments VALUES (4, '広報部', '福岡');
INSERT INTO employees VALUES (1, '田中太郎', 1, '2020-04-01', 350000, 'tanaka@example.com');
INSERT INTO employees VALUES (2, '佐藤花子', 2, '2021-04-01', 400000, 'sato@example.com');
INSERT INTO employees VALUES (3, '鈴木一郎', 2, '2022-04-01', 320000, 'suzuki@example.com');
INSERT INTO employees VALUES (4, '高橋美咲', 3, '2023-04-01', 280000, 'takahashi@example.com');
INSERT INTO employees VALUES (5, '伊藤健太', 1, '2021-10-01', 330000, 'ito@example.com');
INSERT INTO employees VALUES (6, '渡辺あかり', NULL, '2024-01-15', 300000, 'watanabe@example.com');
-- 部門に所属していない社員を見つける
SELECT e.emp_name
FROM employees e
LEFT JOIN departments d ON e.dept_id = d.dept_id
WHERE d.dept_id IS NULL;
-- 社員がいない部門を見つける
SELECT d.dept_name
FROM departments d
LEFT JOIN employees e ON d.dept_id = e.dept_id
WHERE e.emp_id IS NULL;
Step 5: 自己結合
同じテーブル同士を結合する
社員テーブルに「上司ID」があるケースを考える。上司も社員テーブルに存在する。
このように、 同じテーブルを2回参照 して結合するのが 自己結合 である。
CREATE TABLE employees_with_manager (
emp_id INTEGER PRIMARY KEY,
emp_name VARCHAR(50) NOT NULL,
manager_id INTEGER REFERENCES employees_with_manager(emp_id),
salary INTEGER CHECK (salary > 0)
);
INSERT INTO employees_with_manager VALUES (1, '山本部長', NULL, 600000);
INSERT INTO employees_with_manager VALUES (2, '田中課長', 1, 450000);
INSERT INTO employees_with_manager VALUES (3, '佐藤花子', 2, 400000);
INSERT INTO employees_with_manager VALUES (4, '鈴木一郎', 2, 320000);
INSERT INTO employees_with_manager VALUES (5, '高橋美咲', 1, 350000);
-- 自己結合:社員名と上司名を表示
SELECT e.emp_name AS 社員名,
m.emp_name AS 上司名
FROM employees_with_manager e
LEFT JOIN employees_with_manager m ON e.manager_id = m.emp_id;
自己結合のポイント
同じテーブルを2回使うので、 別名が必須 である
上の例では e(社員として)と m(上司として)の2つの別名を付けている
山本部長の manager_id は NULL なので、LEFT JOINを使って上司名を NULL として表示している
上のコードを修正して、上司がいない社員(= 最上位の管理者)だけを表示してみよう。
ヒント:WHERE m.emp_id IS NULL を追加する。
Step 6: 3つ以上のテーブルの結合
JOINを連続して書く
実務では、3つ以上のテーブルを結合することも多い。
JOINを連続して書くことで、複数のテーブルをつなげられる。
CREATE TABLE departments (
dept_id INTEGER PRIMARY KEY,
dept_name VARCHAR(50) NOT NULL UNIQUE,
location VARCHAR(50)
);
CREATE TABLE employees (
emp_id INTEGER PRIMARY KEY,
emp_name VARCHAR(50) NOT NULL,
dept_id INTEGER REFERENCES departments(dept_id),
hire_date DATE NOT NULL,
salary INTEGER CHECK (salary > 0)
);
CREATE TABLE projects (
project_id INTEGER PRIMARY KEY,
project_name VARCHAR(100) NOT NULL,
start_date DATE
);
CREATE TABLE assignments (
emp_id INTEGER REFERENCES employees(emp_id),
project_id INTEGER REFERENCES projects(project_id),
role VARCHAR(50),
PRIMARY KEY (emp_id, project_id)
);
INSERT INTO departments VALUES (1, '営業部', '東京');
INSERT INTO departments VALUES (2, '開発部', '大阪');
INSERT INTO departments VALUES (3, '人事部', '東京');
INSERT INTO employees VALUES (1, '田中太郎', 1, '2020-04-01', 350000);
INSERT INTO employees VALUES (2, '佐藤花子', 2, '2021-04-01', 400000);
INSERT INTO employees VALUES (3, '鈴木一郎', 2, '2022-04-01', 320000);
INSERT INTO employees VALUES (4, '高橋美咲', 3, '2023-04-01', 280000);
INSERT INTO projects VALUES (1, 'ECサイト開発', '2024-01-01');
INSERT INTO projects VALUES (2, '社内システム改修', '2024-04-01');
INSERT INTO assignments VALUES (1, 1, 'リーダー');
INSERT INTO assignments VALUES (2, 1, 'メンバー');
INSERT INTO assignments VALUES (3, 1, 'メンバー');
INSERT INTO assignments VALUES (2, 2, 'リーダー');
INSERT INTO assignments VALUES (4, 2, 'メンバー');
-- 3テーブル結合:社員名、部門名、プロジェクト名を表示
SELECT e.emp_name, d.dept_name, p.project_name, a.role
FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id
INNER JOIN assignments a ON e.emp_id = a.emp_id
INNER JOIN projects p ON a.project_id = p.project_id
ORDER BY p.project_name, a.role;
テーブル間の関係
assignments は社員とプロジェクトの 中間テーブル である。
社員とプロジェクトは 多対多 の関係にあり、中間テーブルを介して結合する(詳しくは第9章で学ぶ)。
Step 7: JOINとWHERE、GROUP BYの組み合わせ
JOINした結果をWHEREで絞り込む
JOINで結合した結果に対して、WHEREで条件を指定できる。
CREATE TABLE departments (
dept_id INTEGER PRIMARY KEY,
dept_name VARCHAR(50) NOT NULL UNIQUE,
location VARCHAR(50)
);
CREATE TABLE employees (
emp_id INTEGER PRIMARY KEY,
emp_name VARCHAR(50) NOT NULL,
dept_id INTEGER REFERENCES departments(dept_id),
hire_date DATE NOT NULL,
salary INTEGER CHECK (salary > 0)
);
INSERT INTO departments VALUES (1, '営業部', '東京');
INSERT INTO departments VALUES (2, '開発部', '大阪');
INSERT INTO departments VALUES (3, '人事部', '東京');
INSERT INTO employees VALUES (1, '田中太郎', 1, '2020-04-01', 350000);
INSERT INTO employees VALUES (2, '佐藤花子', 2, '2021-04-01', 400000);
INSERT INTO employees VALUES (3, '鈴木一郎', 2, '2022-04-01', 320000);
INSERT INTO employees VALUES (4, '高橋美咲', 3, '2023-04-01', 280000);
INSERT INTO employees VALUES (5, '伊藤健太', 1, '2021-10-01', 330000);
INSERT INTO employees VALUES (6, '渡辺あかり', 2, '2023-07-01', 300000);
-- JOINとWHERE:東京勤務の社員を表示
SELECT e.emp_name, d.dept_name, d.location
FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id
WHERE d.location = '東京';
-- JOINとGROUP BY:部門ごとの社員数と平均給与
SELECT d.dept_name,
COUNT(*) AS 社員数,
ROUND(AVG(e.salary)) AS 平均給与
FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id
GROUP BY d.dept_name
ORDER BY 平均給与 DESC;
-- JOINとGROUP BY + HAVING:社員が2人以上の部門
SELECT d.dept_name,
COUNT(*) AS 社員数
FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id
GROUP BY d.dept_name
HAVING COUNT(*) >= 2;
SQLの実行順序(JOIN含む)
JOINを含むSQLの実行順序は以下の通りである。
順番 句 処理内容 1 FROM + JOIN テーブルを結合する 2 WHERE 行を絞り込む 3 GROUP BY グループ化する 4 HAVING グループを絞り込む 5 SELECT 列を選択・計算する 6 ORDER BY 並び替える 7 LIMIT 件数を制限する
JOINはWHEREよりも先に実行される。そのため、 結合条件はON句に書き、絞り込み条件はWHEREに書く のが正しい使い分けである。
Step 8: 実践課題
課題1:社員の詳細情報を表示しよう
社員名、部門名、プロジェクト名、役割を一覧表示するSQLを書こう。
プロジェクトに参加していない社員も表示すること(LEFT JOINを使う)。
課題2:部門ごとの集計を表示しよう
部門名ごとの社員数と平均給与を表示するSQLを書こう。
社員がいない部門も表示すること。
課題3:上司と部下の関係を表示しよう
自己結合を使って、各社員とその上司の名前を表示するSQLを書こう。
CREATE TABLE departments (
dept_id INTEGER PRIMARY KEY,
dept_name VARCHAR(50) NOT NULL UNIQUE,
location VARCHAR(50)
);
CREATE TABLE employees (
emp_id INTEGER PRIMARY KEY,
emp_name VARCHAR(50) NOT NULL,
dept_id INTEGER REFERENCES departments(dept_id),
manager_id INTEGER REFERENCES employees(emp_id),
hire_date DATE NOT NULL,
salary INTEGER CHECK (salary > 0)
);
CREATE TABLE projects (
project_id INTEGER PRIMARY KEY,
project_name VARCHAR(100) NOT NULL
);
CREATE TABLE assignments (
emp_id INTEGER REFERENCES employees(emp_id),
project_id INTEGER REFERENCES projects(project_id),
role VARCHAR(50),
PRIMARY KEY (emp_id, project_id)
);
INSERT INTO departments VALUES (1, '営業部', '東京');
INSERT INTO departments VALUES (2, '開発部', '大阪');
INSERT INTO departments VALUES (3, '人事部', '東京');
INSERT INTO departments VALUES (4, '広報部', '福岡');
INSERT INTO employees VALUES (1, '山本部長', 1, NULL, '2015-04-01', 600000);
INSERT INTO employees VALUES (2, '田中課長', 2, 1, '2018-04-01', 450000);
INSERT INTO employees VALUES (3, '佐藤花子', 2, 2, '2021-04-01', 400000);
INSERT INTO employees VALUES (4, '鈴木一郎', 2, 2, '2022-04-01', 320000);
INSERT INTO employees VALUES (5, '高橋美咲', 3, 1, '2023-04-01', 280000);
INSERT INTO employees VALUES (6, '渡辺あかり', NULL, NULL, '2024-01-15', 300000);
INSERT INTO projects VALUES (1, 'ECサイト開発');
INSERT INTO projects VALUES (2, '社内システム改修');
INSERT INTO assignments VALUES (2, 1, 'リーダー');
INSERT INTO assignments VALUES (3, 1, 'メンバー');
INSERT INTO assignments VALUES (4, 1, 'メンバー');
INSERT INTO assignments VALUES (2, 2, 'リーダー');
INSERT INTO assignments VALUES (5, 2, 'メンバー');
-- 課題1:社員名、部門名、プロジェクト名、役割を表示
-- プロジェクト未参加の社員もLEFT JOINで表示すること
-- ここにSQLを書こう
-- 課題2:部門名ごとの社員数と平均給与を表示
-- 社員がいない部門も表示すること
-- ここにSQLを書こう
-- 課題3:各社員とその上司の名前を表示(自己結合)
-- ここにSQLを書こう
SELECT 'ここに課題1〜3のSQLを書いてみよう' AS message;
まとめ
この章では、 テーブルの結合(JOIN) について学んだ。
🎯 達成できたこと
✅ JOINの必要性を説明できる
✅ INNER JOINで2つのテーブルを結合できる
✅ テーブルに別名を付けられる
✅ LEFT OUTER JOINで外部結合ができる
✅ 自己結合ができる
✅ 3つ以上のテーブルを結合できる
✅ JOINとWHERE、GROUP BYを組み合わせられる
📚 学んだ内容
テーブルを正規化(分割)したから、JOINで結合する必要がある
INNER JOINは両方のテーブルに一致するデータだけを返す
LEFT JOINは左側テーブルの全データを返し、一致しない右側はNULLになる
自己結合は同じテーブルを2回参照して結合する(別名が必須)
JOINはWHERE、GROUP BY、HAVINGと組み合わせて使える
🚀 次のステップ
次の章では、 ER図とデータベース設計 について学ぶ。
テーブルの関係を視覚的に表現する方法と、設計のプロセスを学ぶ。
💡 よくある質問
Q1: INNER JOINとLEFT JOINのどちらを使えばいい?
A: 「一致しないデータも表示したいか」で判断する。例えば「全社員を表示したいが、部門名がない場合もある」ならLEFT JOIN、「部門に所属している社員だけでよい」ならINNER JOINを使う。迷ったらLEFT JOINの方が安全(データの取りこぼしがない)である。
Q2: RIGHT JOINは使わないの?
A: RIGHT JOINはLEFT JOINの左右を入れ替えたものであり、FROMに書くテーブルの順序を変えればLEFT JOINで代用できる。読みやすさのため、LEFT JOINに統一するのが一般的である。
Q3: JOINの結合条件を間違えるとどうなる?
A: 結合条件が不適切だと 直積 (CROSS JOIN)のような結果になり、意図しない大量のデータが返される。例えば社員5人と部門3つでON句なしにJOINすると15行(5×3)になる。必ずON句で正しい結合条件を指定しよう。
Q4: JOINを使うとパフォーマンスは大丈夫?
A: 適切なインデックス(特に外部キー列)があれば、JOINのパフォーマンスは十分に速い。数万件程度のデータであれば、JOINを3〜4つ連続しても問題ない。パフォーマンスが気になるのは数百万件以上のデータを扱う場合である。
Q5: AIにJOINのSQLを書かせてもいい?
A: 複雑なJOINはAIに書かせるのが効率的である。ただし、INNER JOINとLEFT JOINの使い分けが要件に合っているか、結合条件が正しいかは必ずレビューしよう。特に「NULLのデータを含めるかどうか」は要件次第なので、AIに正確に伝える必要がある。
練習問題
この章の内容を理解できたか確認しよう。
テーブルの結合(JOIN)が必要な理由として正しいものを選べ。
採点する 諦めて解答を表示する(達成済みステータスを外します)
解答・解説を見る
正解 B. 正規化によって分割されたテーブルの関連データをまとめて取得するため
解説 正規化によってデータは複数のテーブルに分割されている。
JOINはその分割されたテーブルのデータをまとめて取得するための操作である。
具体例 :
employees テーブルには dept_id しかなく、部門名(dept_name)は departments テーブルにある。
「社員名と所属部門名」を一度に取得したい場合、2つのテーブルをJOINする必要がある。
SELECT e.emp_name, d.dept_name
FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id;
JOINの種類 :
INNER JOIN: 両テーブルに一致する行のみ取得
LEFT JOIN: 左テーブルの全行を取得(右テーブルに一致なければNULL)
RIGHT JOIN: 右テーブルの全行を取得(左テーブルに一致なければNULL)
FULL OUTER JOIN: 両テーブルの全行を取得
問題2. INNER JOINで2つのテーブルを結合できる
テーブル名・カラム名は 小文字 で入力する(例: employees, dept_id)
SQLキーワードは 大文字 で入力する(例: SELECT, FROM, WHERE)
正しい例: SELECT emp_name FROM employees WHERE dept_id = 1;
employees テーブルと departments テーブルを dept_id で内部結合し、
emp_name と dept_name を取得するSQL文を完成させよ。
SELECT e.emp_name, d.dept_name
FROM employees e
departments d ON e.dept_id = d.dept_id;
採点する 諦めて解答を表示する(達成済みステータスを外します)
解答・解説を見る
解答例 SELECT e.emp_name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id = d.dept_id;
解説 INNER JOIN テーブル名 ON 結合条件 で内部結合を行う。
基本構文:
SELECT テーブル別名1.列名, テーブル別名2.列名
FROM テーブル名1 別名1
INNER JOIN テーブル名2 別名2 ON 別名1.外部キー = 別名2.主キー;
INNER JOIN の特性 :
両テーブルで結合条件が一致する行のみを返す
一方のテーブルに対応する行がない場合はその行が除外される
employees の中で dept_id=NULL の 渡辺あかり は INNER JOIN では除外される
ON 句 :
外部キーと参照先の主キーを等号(=)で結ぶのが基本パターン
ON e.dept_id = d.dept_id: 社員の部門IDと部門テーブルの部門IDが一致する行を結合
テーブル名・カラム名は 小文字 で入力する(例: employees, dept_id)
SQLキーワードは 大文字 で入力する(例: SELECT, FROM, WHERE)
正しい例: SELECT emp_name FROM employees WHERE dept_id = 1;
employees テーブルに e という別名を付けて、emp_name を取得するSQL文を完成させよ。
SELECT
.emp_name
FROM employees
;
採点する 諦めて解答を表示する(達成済みステータスを外します)
解答・解説を見る
解答例 SELECT e.emp_name FROM employees e;
解説 テーブルに別名(エイリアス)を付けるには FROM テーブル名 別名 と記述する。
基本構文:
SELECT 別名.列名 FROM テーブル名 別名;
テーブル別名の用途 :
JOINで同名の列(例: dept_id)が複数テーブルにある場合に区別できる
長いテーブル名を短縮して記述量を減らせる
自己結合(同じテーブルを2回JOIN)では必須
命名規則 :
慣例としてテーブル名の頭文字1〜2文字を使うことが多い(例: employees → e、departments → d)
AS を付けて employees AS e と書くこともできる
JOINを使うときはテーブル別名を付けるのが一般的である。
問題4. LEFT OUTER JOINで外部結合ができる
テーブル名・カラム名は 小文字 で入力する(例: employees, dept_id)
SQLキーワードは 大文字 で入力する(例: SELECT, FROM, WHERE)
正しい例: SELECT emp_name FROM employees WHERE dept_id = 1;
部門未所属の社員も含め、全社員の emp_name と dept_name を取得するSQL文を完成させよ。
(部門がない場合は dept_name がNULLとなる)
SELECT e.emp_name, d.dept_name
FROM employees e
JOIN departments d ON e.dept_id = d.dept_id;
ヒントを表示部門未所属の社員も含めるには INNER ではなく何が必要か考えよう
採点する 諦めて解答を表示する(達成済みステータスを外します)
解答・解説を見る
解答例 SELECT e.emp_name, d.dept_name FROM employees e LEFT JOIN departments d ON e.dept_id = d.dept_id;
解説 LEFT JOIN(または LEFT OUTER JOIN)は左テーブルの全行を取得し、
右テーブルに一致がない場合はNULLを返す。
基本構文:
SELECT 列名
FROM 左テーブル e
LEFT JOIN 右テーブル d ON 結合条件;
INNER JOIN との違い :
INNER JOIN: 両テーブルに一致する行のみ(渡辺あかりは除外される)
LEFT JOIN: 左テーブル(employees)の全行(渡辺あかりも含まれ、dept_nameはNULL)
結果イメージ :
| emp_name | dept_name |
|------------|-----------|
| 田中太郎 | 営業部 |
| 鈴木花子 | 開発部 |
| 佐藤次郎 | 開発部 |
| 渡辺あかり | NULL | ← LEFT JOIN なので含まれる
| 中村健一 | 営業部 |
問題5. INNER JOINとLEFT JOINの違いを説明できる
INNER JOIN と LEFT JOIN の違いとして正しいものを選べ。
採点する 諦めて解答を表示する(達成済みステータスを外します)
解答・解説を見る
正解 A. INNER JOIN は両テーブルに一致する行のみ取得し、LEFT JOIN は左テーブルの全行を取得する(右テーブルに一致がなければNULL)
解説 INNER JOIN (内部結合):
両テーブルで結合条件が一致する行のみを返す
一方に対応する行がなければその行は除外される
employees の中で dept_id=NULL の社員(渡辺あかり)は除外される
LEFT JOIN (左外部結合):
左テーブル(FROM に書いたテーブル)の全行を返す
右テーブルに一致がない場合は NULL で埋める
渡辺あかりも結果に含まれ、dept_name は NULL になる
使い分け :
関連データが必ず存在する場合 → INNER JOIN
関連データが存在しない行も含めたい場合 → LEFT JOIN
例: 「全社員と、所属部門名(未所属の場合はNULL)を取得」→ LEFT JOIN
テーブル名・カラム名は 小文字 で入力する(例: employees, dept_id)
SQLキーワードは 大文字 で入力する(例: SELECT, FROM, WHERE)
正しい例: SELECT emp_name FROM employees WHERE dept_id = 1;
employees テーブルを e1、e2 の2つの別名で自己結合し、
同じ部門に所属する社員のペアを取得するSQL文を完成させよ。
(e1.emp_id < e2.emp_id で重複の組み合わせを除去する)
SELECT e1.emp_name AS 社員1, e2.emp_name AS 社員2
FROM employees
INNER JOIN employees e2 ON e1.dept_id = e2.dept_id AND e1.emp_id < e2.emp_id;
ヒントを表示同じテーブルを2つの別名で使うのが自己結合のポイント
採点する 諦めて解答を表示する(達成済みステータスを外します)
解答・解説を見る
解答例 SELECT e1.emp_name AS 社員1, e2.emp_name AS 社員2 FROM employees e1 INNER JOIN employees e2 ON e1.dept_id = e2.dept_id AND e1.emp_id < e2.emp_id;
解説 自己結合は同じテーブルを異なる別名で複数回参照する結合である。
基本構文:
SELECT e1.列名, e2.列名
FROM テーブル名 e1
INNER JOIN テーブル名 e2 ON 結合条件;
自己結合の用途 :
社員同士の関係(同じ部門に所属する社員のペアなど)
階層構造(上司・部下の関係)
同一テーブル内の比較
重複排除の条件 :
e1.emp_id < e2.emp_id という条件で
(田中, 中村) のペアのみ返す
(中村, 田中) の逆順の重複を除外する
この条件がないと同じペアが2回表示されてしまう。
テーブル名・カラム名は 小文字 で入力する(例: employees, dept_id)
SQLキーワードは 大文字 で入力する(例: SELECT, FROM, WHERE)
正しい例: SELECT emp_name FROM employees WHERE dept_id = 1;
employees、departments、assignments の3テーブルを結合して、
社員名・部門名・担当プロジェクトIDを取得するSQL文を完成させよ。
SELECT e.emp_name, d.dept_name, a.project_id
FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id
assignments a ON
.emp_id = a.emp_id;
ヒントを表示3テーブルの結合はINNER JOINを2回連続して書く
採点する 諦めて解答を表示する(達成済みステータスを外します)
解答・解説を見る
解答例 SELECT e.emp_name, d.dept_name, a.project_id FROM employees e INNER JOIN departments d ON e.dept_id = d.dept_id INNER JOIN assignments a ON e.emp_id = a.emp_id;
解説 3つ以上のテーブルを結合するには INNER JOIN ... ON ... を連続して記述する。
基本構文:
FROM テーブル1 t1
INNER JOIN テーブル2 t2 ON t1.外部キー = t2.主キー
INNER JOIN テーブル3 t3 ON t1.外部キー = t3.主キー;
-- または t2.外部キー = t3.主キー(結合元は状況による)
各結合条件 :
employees JOIN departments: e.dept_id = d.dept_id(社員の所属部門)
employees JOIN assignments: e.emp_id = a.emp_id(社員のアサインメント)
注意点 :
各 JOIN の ON 条件に正しいテーブル別名と列名を使う
同名の列が複数テーブルに存在する場合は必ず 別名.列名 で区別する
assignments は employees と直接関係しているため e.emp_id = a.emp_id が結合条件
問題8. JOINとWHERE、GROUP BYを組み合わせられる
テーブル名・カラム名は 小文字 で入力する(例: employees, dept_id)
SQLキーワードは 大文字 で入力する(例: SELECT, FROM, WHERE)
正しい例: SELECT emp_name FROM employees WHERE dept_id = 1;
部門名(dept_name)と部門ごとの社員数を取得するSQL文を完成させよ。
SELECT d.dept_name, COUNT(*) AS 社員数
FROM departments d
INNER JOIN employees e ON d.dept_id = e.dept_id
d.
;
ヒントを表示JOIN後のデータをグループ集計するには GROUP BY を使う
採点する 諦めて解答を表示する(達成済みステータスを外します)
解答・解説を見る
解答例 SELECT d.dept_name, COUNT(*) AS 社員数 FROM departments d INNER JOIN employees e ON d.dept_id = e.dept_id GROUP BY d.dept_name;
解説 JOIN と GROUP BY を組み合わせることで、結合後のデータをグループ集計できる。
SQL句の実行順序 :
FROM → JOIN → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT
GROUP BY に使用できる列 :
GROUP BY に指定した列のみ SELECT に書ける(集約関数以外)
d.dept_name で GROUP BY しているため SELECT に d.dept_name を書ける
注意点 :
GROUP BY d.dept_id でも正しいが、SELECT 句に dept_name を表示したいため dept_name でグループ化する
INNER JOIN なので部門に所属する社員のみ数えられる
LEFT JOIN に変えると社員が0人の部門も結果に含まれる
テーブル名・カラム名は 小文字 で入力する(例: employees, dept_id)
SQLキーワードは 大文字 で入力する(例: SELECT, FROM, WHERE)
正しい例: SELECT emp_name FROM employees WHERE dept_id = 1;
「開発部(dept_name='開発部')に所属し、かつプロジェクトにアサインされている社員の名前と役割を取得せよ」
を実装するSQL文を完成させよ。
SELECT e.emp_name, a.role
FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id
assignments a ON e.emp_id = a.emp_id
d.dept_name = '開発部';
ヒントを表示3テーブルをJOINした後にWHEREで絞り込む順序を考えよう
採点する 諦めて解答を表示する(達成済みステータスを外します)
解答・解説を見る
解答例 SELECT e.emp_name, a.role FROM employees e INNER JOIN departments d ON e.dept_id = d.dept_id INNER JOIN assignments a ON e.emp_id = a.emp_id WHERE d.dept_name = '開発部';
解説 複数テーブルのJOINと WHERE による絞り込みを組み合わせることで、
複雑な条件のデータを取得できる。
この問題の解法 :
「アサインされている社員」→ employees と assignments を INNER JOIN
「開発部に所属」→ employees と departments を INNER JOIN して WHERE dept_name = '開発部'
INNER JOIN の自動フィルタリング :
INNER JOIN assignments a ON e.emp_id = a.emp_id は
assignments に存在する社員のみを返す(アサインされていない社員は除外)
これにより「アサインされている社員のみ」が自動的に絞り込まれる
JOINとWHEREの組み合わせ :
JOINで関連テーブルを結合した後、WHEREで条件を絞り込む。
JOINはテーブルを繋ぐ、WHEREは結果を絞り込む、という役割分担を意識すると良い。