前回、乗組員の情報はcrewテーブルに、任務の情報はmissionsテーブルに分けました。missionsテーブルの crew_id は、ただの数字(2とか4とか)です。ここから「担当はケンジです」と名前で表示するには、SQLでどうすればいいでしょう?
crew_id の数字を、crewテーブルの id と照らし合わせれば、名前が分かりそうですよね。まさにそれを自動でやってくれる仕組みが、今回学ぶJOINです。
テーブルをつなぐ INNER JOIN
2つの表を結びつけるには、INNER JOINを使います。missionsテーブルとcrewテーブルを、担当者でつないでみましょう。
SELECT missions.title, crew.name
FROM missions
INNER JOIN crew ON missions.crew_id = crew.id;
結果:
| title | name |
|---|---|
| 火星資源調査 | ケンジ |
| タイタン氷床探査 | ソラ |
| エウロパ生命探査 | レイ |
| ケレス採掘権交渉 | サクラ |
| 金星大気観測 | ユミ |
| 火星コロニー建設支援 | リョウ |
| ケレス医療支援 | ハルト |
crew_id という数字だけだった任務の担当者が、ちゃんと名前で表示されました。書き方の流れはこうです。
FROM missions― まず基準となる表(missions)を決めるINNER JOIN crew― そこにcrewテーブルをつなげるON missions.crew_id = crew.id― どの行とどの行を「同じ担当者」とみなすか、条件を指定する
ON句の読み方
ON句は、JOINの心臓部です。missions.crew_id = crew.id は、「missionsテーブルのcrew_id列の値と、crewテーブルのid列の値が一致する行同士を、1行につなげてください」という指示です。
たとえばmissionsの1行目は crew_id = 2。crewテーブルで id = 2 の行を探すと、名前は「ケンジ」。この2つの行が横に並べられて、1行の結果になります。ON句がなければ、SQLはどの行とどの行をつなげればいいか分からず、結合になりません。
テーブル名.列名 で列を指定する
先ほどのSQLで missions.title crew.name のように、列名の前に「テーブル名.」を付けているのに気づいたでしょうか。これは修飾と呼ばれる書き方です。
なぜ必要かというと、crewテーブルにも id があり、missionsテーブルにも id があるように、複数のテーブルに同じ名前の列が存在することがあるからです。JOINした状態で単に id とだけ書くと、SQLはどちらの表の id か判断できずエラーになってしまいます。
-- ○ 正しい:どちらの表のidか明確
SELECT crew.id, missions.id
FROM missions
INNER JOIN crew ON missions.crew_id = crew.id;
-- × あいまい:JOIN後は id だけでは通らないことがある
SELECT id
FROM missions
INNER JOIN crew ON missions.crew_id = crew.id;
「テーブル名.列名」で書けば迷わない——JOINを使うときの基本ルールとして覚えておきましょう。
複数のテーブルを結合する
INNER JOINは、3つ以上のテーブルをつなげることもできます。missionsに、crewとplanetsの両方をつなげてみましょう。
planets テーブル:
| id | name | distance | population |
|---|---|---|---|
| 1 | 火星 | 7800 | 4500000 |
| 2 | 金星 | 4100 | 0 |
| 3 | タイタン | 128000 | 1200 |
| 4 | エウロパ | 96000 | 300 |
| 5 | ケレス | 55000 | 50 |
| 6 | ネレイド | 210000 | 0 |
SELECT missions.title, crew.name, planets.name, missions.reward
FROM missions
INNER JOIN crew ON missions.crew_id = crew.id
INNER JOIN planets ON missions.planet_id = planets.id;
結果:
| title | name | name | reward |
|---|---|---|---|
| 火星資源調査 | ケンジ | 火星 | 50000 |
| タイタン氷床探査 | ソラ | タイタン | 80000 |
| エウロパ生命探査 | レイ | エウロパ | 95000 |
| ケレス採掘権交渉 | サクラ | ケレス | 60000 |
| 金星大気観測 | ユミ | 金星 | 40000 |
| 火星コロニー建設支援 | リョウ | 火星 | 70000 |
| ケレス医療支援 | ハルト | ケレス | 65000 |
INNER JOIN を続けて2回書くだけで、任務・担当者・目的地の3つの表を1行に並べられました。「name」列が2つ出て紛らわしいのも、crew.name・planets.name と修飾しているからこそ、SQL自身はきちんと区別できています。
INNER JOINの ON 句には、どんな役割があるでしょう?
答えを見る
どの行とどの行を「同じもの」とみなしてつなげるか、その条件を指定する役割です。
たとえば ON missions.crew_id = crew.id は、「missionsのcrew_idと、crewのidが一致する行同士をつなげる」という指示です。ON句がなければ、SQLはどの行を結びつければいいか判断できません。
数字だけだった crew_id が、JOINのおかげで名前になって出てくる——これがJOINの醍醐味だよ。「FROMで基準を決めて、INNER JOINでつなげて、ONで条件を書く」。この3点セットを覚えておこう!
/sql/game/ の SQL DIVER で、実際にINNER JOINをタイプして試してみましょう。ON 句を自分の手で書く感覚を、ぜひ体に覚え込ませてください。