基本情報のSQL結合(JOIN)がわからない!内部結合・外部結合を図解
JOINが出てくると、2つの表がどう組み合わさって、何行の結果になるのか想像できない。
SQLの問題で、FROMの後ろに表が2つ並んだとたん、手が止まっていませんか?
先に答えをお伝えします。
JOIN(結合)は、2つの表の行を、決めた条件で組み合わせて1つの表にする操作です。内部結合は、相手の表に組み合わせる行が見つかったものだけを残します。外部結合は、相手が見つからなかった行も残し、足りない列をNULLで埋めます。
この違いさえ押さえれば、結果の表は落ち着いて予測できます。この記事では、この記事のために作った小さな2つの表を使い、どの行が残り、どこにNULLが入るのかを順番に確かめていきます。
基本情報技術者試験の全体像を先に確かめたい人は、こちらの親記事が参考になります。
【関連記事】基本情報技術者試験とは?試験内容・難易度・勉強法を初心者向けに解説
JOIN(結合)とは?2つの表を1つにまとめる操作¶
データベースでは、同じ情報を何度も書かずに済むよう、データを複数の表に分けて保存します。社員の情報と部署の情報を、別々の表にしておくのがその例です。
分けて保存したデータを、画面や帳票で一緒に見たいときに使うのがJOINです。2つの表の共通する列を手がかりに、行と行をつなぎ合わせます。
この記事で使う2つの表¶
ここからは、次の社員表と部署表を使います。社員表の部署コードを見れば、その社員がどの部署にいるのかが分かる、という関係です。
まず社員表です。小川さんは配属前なので、部署コードが空になっています。
| 社員番号 | 氏名 | 部署コード |
|---|---|---|
| 101 | 青木 | D1 |
| 102 | 井上 | D2 |
| 103 | 上田 | D1 |
| 104 | 江藤 | D3 |
| 105 | 小川 | NULL |
NULLとは、値が入っていない、または分からないことを表す特別な印です。0や空白の文字とは違い、何も値が無い状態を指します。
次に部署表です。社員表に出てくるD3はこの表に無く、逆にD4の企画部には社員がいません。
| 部署コード | 部署名 |
|---|---|
| D1 | 営業 |
| D2 | 開発 |
| D4 | 企画 |
わざと、相手が見つからない行を両方の表に入れてあります。内部結合と外部結合の違いは、こうした行の扱いに表れるからです。
結合条件は ON の後ろに書く¶
JOINを使うSQLでは、どの列とどの列が等しい行どうしをつなぐかを、ONの後ろに書きます。これを結合条件と呼びます。
SELECT 社員.氏名, 部署.部署名
FROM 社員 INNER JOIN 部署
ON 社員.部署コード = 部署.部署コード
社員.部署コードのように、表の名前と列の名前をピリオドでつなぐ書き方があります。2つの表に同じ名前の列があるので、どちらの表の列なのかをはっきりさせるためです。
試験では、FROM 社員 E のように表に短い別名を付け、E.部署コードと書く問題もよく見かけます。別名は呼び名を短くしただけなので、意味は変わりません。
内部結合(INNER JOIN)|相手が見つかった行だけが残る¶
内部結合は、結合条件に合う相手が見つかった行どうしだけを組み合わせます。相手がいない行は、どちらの表のものでも結果から外れます。
1行ずつ相手を探してみる¶
上のSQLを、社員表の1行目から順に追ってみましょう。社員1人ずつについて、部署表から同じ部署コードの行を探します。
| 社員 | 部署コード | 部署表に相手はいるか | 結果に残るか |
|---|---|---|---|
| 青木 | D1 | D1 営業がある | 残る |
| 井上 | D2 | D2 開発がある | 残る |
| 上田 | D1 | D1 営業がある | 残る |
| 江藤 | D3 | D3は無い | 残らない |
| 小川 | NULL | NULLとは一致しない | 残らない |
結果は、青木・営業、井上・開発、上田・営業の3行です。部署表の企画部には相手になる社員がいないので、こちらも結果に出てきません。
小川さんの行が外れる理由は、少し注意が必要です。NULLは値が無い状態なので、どんな値と比べても等しいとは判断されません。結合条件の = は成り立たず、相手が見つからない扱いになります。
結合の結果は図にすると分かりやすい¶
内部結合は、2つの表の行を3つのグループに分けて考えると整理しやすくなります。社員表だけにある行、両方に相手がいる行、部署表だけにある行の3つです。
[社員表だけにある行] [両方に相手がいる行] [部署表だけにある行]
江藤(D3) 青木 - 営業 企画(D4)
小川(NULL) 井上 - 開発
上田 - 営業
↑ 内部結合で残る部分
真ん中のグループだけが、内部結合で残る行です。左右のグループをどう扱うかで、外部結合の種類が決まります。
FROMに表を並べる書き方¶
INNER JOINと書かずに、FROMに表をカンマで並べ、WHEREに結合条件を書く形もあります。基本情報の問題では、こちらの書き方を見ることも少なくありません。
SELECT 社員.氏名, 部署.部署名
FROM 社員, 部署
WHERE 社員.部署コード = 部署.部署コード
このSQLの結果は、先ほどの内部結合とまったく同じ3行になります。WHEREの条件で、部署コードが等しい組み合わせだけを残しているからです。
FROMとWHEREの読み方そのものに不安がある人は、先にこちらの記事で基本を確かめておくと読みやすくなります。
【関連記事】基本情報のSQL問題の解き方|SELECT・WHERE・ORDER BYを例題で解説
外部結合(OUTER JOIN)|相手がいない行もNULLで残る¶
外部結合は、相手が見つからなかった行も結果に残す結合です。残した行の、相手の表の列には値が無いので、NULLが入ります。
外部結合には、どちらの表の行を必ず残すかによって3つの種類があります。違いを先に表で比べておきましょう。
| 種類 | 必ず残る行 | この記事の表での行数 |
|---|---|---|
| 内部結合(INNER JOIN) | 相手が見つかった行だけ | 3行 |
| 左外部結合(LEFT OUTER JOIN) | 左の表(社員)のすべての行 | 5行 |
| 右外部結合(RIGHT OUTER JOIN) | 右の表(部署)のすべての行 | 4行 |
| 完全外部結合(FULL OUTER JOIN) | 両方の表のすべての行 | 6行 |
左と右は、SQLの中でJOINより前に書いた表が左、後ろに書いた表が右です。OUTERは省略して、LEFT JOINのように書いても同じ意味になります。
左外部結合(LEFT JOIN)の結果¶
試験でいちばんよく見かけるのが、左外部結合です。社員表を左に置いて、部署表と左外部結合してみます。
SELECT 社員.氏名, 部署.部署名
FROM 社員 LEFT OUTER JOIN 部署
ON 社員.部署コード = 部署.部署コード
左の社員表は、相手がいてもいなくても全員が残ります。相手が見つからない江藤さんと小川さんの部署名には、NULLが入ります。
| 氏名 | 部署名 |
|---|---|
| 青木 | 営業 |
| 井上 | 開発 |
| 上田 | 営業 |
| 江藤 | NULL |
| 小川 | NULL |
内部結合の3行に、相手のいない2行が足されて5行になりました。一方、部署表だけにある企画部は、左の表ではないので残りません。
右外部結合と完全外部結合¶
右外部結合は、右の表のすべての行を残します。同じSQLのLEFTをRIGHTに変えると、部署表の3部署が必ず残ります。
結果は、青木・営業、上田・営業、井上・開発の3行に、氏名がNULLで部署名が企画の1行を足した4行です。営業部には社員が2人いるので、営業の行は2回出てきます。
完全外部結合は、左右どちらの行も残します。内部結合の3行に、江藤・NULL、小川・NULL、NULL・企画の3行を足して6行です。
右外部結合は、表を書く順番を入れ替えれば左外部結合で書き直せます。部署 LEFT JOIN 社員と書けば、社員 RIGHT JOIN 部署と同じ行が残ります。迷ったら、どちらの表を必ず残したいのかを先に決めると整理できます。
結合の結果を予測する練習問題¶
ここまでの内容を使って、結果を予測する練習をしてみましょう。答えを見る前に、行ごとに相手を探す表を紙に書いてから考えてみてください。
練習1|相手のいない行を探す¶
SELECT 社員.氏名
FROM 社員 LEFT OUTER JOIN 部署
ON 社員.部署コード = 部署.部署コード
WHERE 部署.部署コード IS NULL
まず左外部結合で5行を作り、そのあとWHEREで行を絞ります。IS NULLは、値がNULLかどうかを調べる書き方です。
部署表の列がNULLになっているのは、相手が見つからなかった江藤さんと小川さんの行です。結果はこの2人になります。
この形は、所属先が登録されていない社員を探すときなどに使われます。外部結合とIS NULLの組み合わせは、相手のいない行を見つける定番の書き方として覚えておきましょう。
なお、条件を 部署.部署コード = NULL と書くと、どの行も残りません。NULLとの比較に = を使っても成り立たないので、NULLを調べるときは必ずIS NULLを使います。
練習2|結果の行数を数える¶
SELECT 部署.部署名, 社員.氏名
FROM 部署 LEFT OUTER JOIN 社員
ON 部署.部署コード = 社員.部署コード
今度は部署表が左です。部署1つずつについて、同じ部署コードの社員を探していきます。
D1の営業には青木さんと上田さんの2人が見つかるので、営業の行が2行できます。D2の開発は井上さんの1行、D4の企画は相手がいないので氏名がNULLの1行です。
結果は合わせて4行になります。結合では、相手が複数見つかると、その数だけ行が増えることに注意しましょう。
結合の問題で間違えやすい点¶
結果が合わなかったときに見直せるよう、つまずきやすい点を表にまとめます。
| 間違えやすい点 | 起きること | 確かめ方 |
|---|---|---|
| 左右の表を取り違える | 残るはずの行が抜ける | JOINの前に書いた表が左、と確かめる |
| NULLどうしが一致すると思う | 内部結合の行が増えてしまう | NULLは = で一致しない、と思い出す |
| 相手が複数いる行を1行と数える | 結果の行数が合わない | 相手の数だけ行が増える、と数え直す |
| = NULLで絞り込む | 結果が0行になる | NULLを調べるときはIS NULLを使う |
| 外部結合の後のWHEREを忘れる | NULLの行が残ったままになる | 結合 → WHERE の順に処理する |
どの間違いも、相手が見つからない行や、相手が2つ以上ある行で起きます。行ごとに相手を探す表を書いておけば、こうした行を見落としにくくなります。
結合を理解すると正規化やほかの問題も読みやすくなる¶
JOINが必要になるのは、データが複数の表に分けて保存されているからです。どういう理由で表を分けるのかを学ぶのが、データベースの正規化です。
表を分ける手順と、分けたときに生まれる利点を知っておくと、結合の問題の意味が見えやすくなります。正規化については、こちらの記事で詳しく解説しています。
【関連記事】基本情報のデータベース正規化とは?第1〜第3正規形を図解で理解
1行ずつ相手を探す力は科目Bでも使える¶
結合の結果を予測するとき、社員1人ずつについて部署表を上から探しました。これは、プログラムで二重の繰返しを使って、2つの配列を突き合わせる処理とよく似ています。
外側の繰返しで社員を1人ずつ取り出し、内側の繰返しで部署表を1行ずつ調べるイメージです。科目Bで出題される擬似言語の問題でも、こうした突き合わせの処理はよく登場します。
擬似言語とは、試験のために決められた書き方でプログラムを表したものです。科目Bの出題内容を知りたい人は、こちらの記事を読んでみてください。
【関連記事】基本情報技術者試験の科目Bとは?擬似言語・アルゴリズム対策を初心者向けに解説
私たちの Giji Academy では、擬似言語の講座を記法の基礎から条件分岐・繰返し・配列・アルゴリズム、科目B対策まで段階的に用意しています。擬似言語シミュレーターを使えば、プログラムをブラウザ上で1行ずつ実行し、変数の値が変わる様子を確かめられます。
一部の教材と入門レベルの練習問題は、無料会員のまま使えます。講座は擬似言語の講座一覧から始められます。
まとめ¶
JOIN(結合)は、2つの表の行を、結合条件に合うものどうしで組み合わせる操作です。結合条件はONの後ろに書き、FROMに表を並べてWHEREに書く形もあります。
内部結合は、相手が見つかった行だけを残します。外部結合は、相手のいない行も残し、足りない列をNULLで埋めます。左外部結合は左の表、右外部結合は右の表、完全外部結合は両方の表の行をすべて残します。
NULLは = では一致せず、調べるときはIS NULLを使います。相手が複数いれば行が増えることも忘れずに確かめましょう。行ごとに相手を探す表を書く習慣を付ければ、結合の問題は落ち着いて解けるようになります。