見出し画像

テーブル結合をわかりやすく解説(INNER JOIN・OUTER JOIN)

この記事では、SQLの中でも特に重要で、実務で必ずと言っていいほど使う「テーブル結合(JOIN)」について解説します。内部結合(INNER JOIN)と外部結合(OUTER JOIN)の仕組みと使い方を、具体例を使ってわかりやすく説明します。

YouTubeでも動画で解説していますので、動画で学びたい方はこちらもどうぞ!


🎓 Udemyで体系的に学びたい方へ

応用情報技術者試験「データベース分野」の対策コースをUdemyで公開中です。イラストとアニメーションで仕組みから丁寧に解説しています。

👉 【応用情報技術者試験】データベース分野・午前(科目A)完全攻略コース


この記事で学べること

  • テーブル結合(JOIN)とは何か? なぜ必要?

  • 内部結合(INNER JOIN)の仕組みとSQLの書き方

  • JOIN時のカラム名の指定方法

  • 外部結合(OUTER JOIN)が必要な場面

  • 左外部結合(LEFT OUTER JOIN)の使い方と具体例

  • 右外部結合(RIGHT OUTER JOIN)の使い方と具体例

  • 内部結合と外部結合の違いと使い分け


テーブル結合とは?

これまでのSQL学習では、1つのテーブルからデータを取得する方法を学んできました。ただ、実際のデータベースでは、データが複数のテーブルに分かれて保存されていることがほとんどです。

テーブル結合(JOIN)とは、複数のテーブルを、あたかも1つの大きなテーブルのように「くっつける」操作のことです。


なぜテーブルは分かれているの?

「そもそも、なんでテーブルって最初から分かれているの?全部まとめて1つの大きなテーブルにすれば、"結合"なんてややこしいこと考えなくて済むんじゃないの?」と思った方もいるかもしれません。鋭い視点ですね!

実際のシステムでは、「ユーザー情報」「注文情報」「商品情報」のように、データが種類ごとに別々のテーブルに分けて保存されています。
これには、しっかりとした理由があります。

データを種類ごとに分けて管理することで、

  • 情報が整理されてスッキリする

  • 同じ情報の重複を減らせる

  • データの更新や削除がしやすくなる

といったメリットがあります。このように、データを整理して重複をなくし、管理しやすくするための考え方を 「正規化(せいきか)」 と呼びます。

さて、テーブルを分けると管理がしやすくなるメリットは分かりました。一方で、私たちが普段「見たい!」と思う情報は、「誰が、いつ、何を注文したか」のように、複数のテーブルを結合した形であることが多いですよね。そこで活躍するのが今回のテーマ、「テーブル結合(JOIN)」です!


テーブル結合の具体例(仕組みのイメージ)

実際にテーブル結合がどのように行われるのか、具体的な例でイメージを掴んでいきましょう。

次の2つのテーブルがあるとします。

usersテーブル(ユーザー情報)

user_id | name
--------------
1 | 佐藤太郎
2 | 鈴木次郎
3 | 高橋三郎

ordersテーブル(注文情報)

order_id | user_id | product_name
---------------------------------
101 | 1 | リンゴ
102 | 2 | みかん
103 | 1 | バナナ

さて、この2つのテーブルから「誰が何を買ったのか?」(ユーザー名と商品名)を知りたい場合、どうすれば良いでしょうか?

ordersテーブルを見ても、ユーザーIDしか分からず名前がありません。逆にusersテーブルを見ても、名前は分かりますが何を買ったかは分かりません。

まさか、ordersテーブルから全注文データを取得して…、usersテーブルから全ユーザーデータを取得して…、2つの結果を画面に並べてuser_idが同じものを目で探して整理する、なんてことはしないですよね。データが3件くらいならできるかもしれませんが、何千・何万件もあったら絶対にやりたくない作業です。

そこで役立つのがテーブル結合(JOIN)です。JOINを使えば、「誰が何を買ったのか」という情報を、1つのSQLで一瞬で取得できます!

結合の仕組み

テーブル同士を意味のある形でくっつけるためには、両方のテーブルに存在する「共通の目印」が必要です。今回のordersテーブルとusersテーブルの場合、その目印となるのが user_id です。

結合の流れを1行ずつ見ていきましょう。

たとえば、ordersテーブルの order_id = 101 の行を見ると、user_id は 1 ですね。JOINはこの user_id = 1 と同じ値を持つ行を、usersテーブルから探します。

usersテーブルの1行目、「佐藤太郎」さんの user_id が 1 ですね。JOINはこのように「同じ user_id を持つレコード同士」を見つけ出して、それらをペアにして横に"ガチャン"とくっつけます。

その結果、「注文ID 101、商品リンゴ、ユーザーID 1」の情報と、「ユーザーID 1、名前 佐藤太郎」の情報が合体して、「佐藤太郎さんがリンゴを買った」という1行の情報が出来上がります。

この処理を全行に対して行うと、最終的な結合結果は次のようになります。

order_id | user_id | product_name | name
----------------------------------------
101 | 1 | リンゴ | 佐藤太郎
102 | 2 | みかん | 鈴木次郎
103 | 1 | バナナ | 佐藤太郎

「誰が何を買ったのか」が一目瞭然になりましたね!

この「共通のカラム(キー)の値が一致する行同士を結びつける」という考え方が、テーブル結合の基本的な動きです。


内部結合(INNER JOIN)

INNER JOINの基本構文

テーブル結合をするには、INNER JOINを使います。書き方はこちらの通りです。

SELECT *
FROM テーブル1
INNER JOIN テーブル2
ON テーブル1.共通カラム = テーブル2.共通カラム;

書き方のポイントをまとめます。

  1. FROM句で、結合の基準となる最初のテーブル(テーブル1)を指定します。

  2. INNER JOINというキーワードを使って、結合したい相手のテーブル(テーブル2)を指定します。

  3. ON句で、「どのカラムを使って2つのテーブルを結びつけるか」という結合条件を書きます。多くの場合、両方のテーブルに共通して存在するカラムを指定し、=(イコール)で結びます。

なお、INNER JOINのINNERは省略して、JOINだけと書くこともできます。実務ではJOINと書くことが多いですが、ここでは分かりやすくINNER JOINと書いていきます。

具体的なSQLの書き方

では、ordersテーブルとusersテーブルを結合して「誰が何を買ったのか?」を取得するSQLを書いてみましょう。

SELECT *
FROM orders
INNER JOIN users ON users.user_id = orders.user_id;
  • FROM ordersで、まずordersテーブルから始めます。

  • INNER JOIN usersと書き、usersテーブルを結合します。

  • ON orders.user_id = users.user_idと書き、両テーブルのuser_idが同じ値を持つ行同士を結びつけます。

このSQLを実行すると、user_idをキーにして2つのテーブルの情報が結びつき、結合された結果が得られます!

SELECT句でカラムを指定する

上のSQL(SELECT *)では、両方のテーブルの全カラムが表示されてしまうため、user_idが2列表示されて少し見づらくなります。

今回の目的は「誰が何を買ったのか?」、つまり「ユーザー名(name)」と「商品名(product_name)」だけを知ることです。
そこで、SELECT句でカラムを指定してみましょう。

SELECT u.name, o.product_name
FROM orders AS o
INNER JOIN users AS u
ON u.user_id = o.user_id;

FROM orders AS o や INNER JOIN users AS u のように、テーブル名の後に AS を使って o や u という短い別名(エイリアス)をつけています。これにより、SELECT句やON句でテーブル名を短く書くことができます。

そして、SELECT句では u.name・o.product_name のように 「テーブルの別名.カラム名」 という形式で書いています。

このSQLを実行すると、結合した結果からnameとproduct_nameのみが取得できます。

name | product_name
-------------------
佐藤太郎 | リンゴ
鈴木次郎 | みかん
佐藤太郎 | バナナ

なぜテーブル名を付ける必要があるのか?

JOINを使う際に テーブル名.カラム名 や エイリアス.カラム名 という書き方をするのは、異なるテーブルに同じ名前のカラムが存在する可能性があるからです。

たとえば、ordersテーブルにもusersテーブルにも user_id カラムがあります。単に SELECT user_id と書いただけでは、SQLは「どちらのテーブルのuser_id?」と混乱してしまい、エラーになる可能性があります。

そのため、JOINを使う際のSELECT句では、どのテーブルのカラムなのかを明示することが基本であり、非常に重要です。


INNER JOINの限界 — 一致しないデータは消える

INNER JOINの基本的な書き方はマスターできました。
ここで、もう少し実践的なケースを考えてみましょう。

ordersテーブルに新しい注文データが追加されたとします。

ordersテーブル(追加後)

order_id | user_id | product_name | 
------------------------------------
101 | 1 | リンゴ | 
102 | 2 | みかん | 
103 | 1 | バナナ | 
104 | 4 | ブドウ | ← 追加

4番目の注文「ブドウ」の user_id は 4 です。しかし、usersテーブルには user_id = 4 のユーザー情報がありません。

この状態でINNER JOINを使って結合したら、結果はどうなるでしょうか?

SELECT *
FROM orders
INNER JOIN users ON orders.user_id = users.user_id;

実行結果:

order_id | user_id | product_name | name
----------------------------------------
101 | 1 | リンゴ | 佐藤太郎
102 | 2 | みかん | 鈴木次郎
103 | 1 | バナナ | 佐藤太郎

ordersテーブルにあったはずの order_id = 104 の「ブドウ」のデータが出力されていませんね。これはなぜでしょうか?

INNER JOINの重要なルール

これが INNER JOIN(内部結合) の最も重要なルールです。

INNER JOINは、ON句で指定された条件を使って両方のテーブルで条件にピッタリ一致する行のペアを探し、そのペアが見つかった行だけを結合して結果に残します

user_id が 1, 2, 3 の注文は、usersテーブルに対応する行が見つかったので結果に残りました。しかし、user_id = 4 の「ブドウ」の注文は、usersテーブルに対応する行が見つからなかったため、最終結果から除外されました。

これがINNER JOIN(内部結合)と呼ばれる理由です。両方のテーブルに共通して存在する、「内側」の情報だけを取り出す結合方法です。


外部結合(OUTER JOIN)が必要な場面

INNER JOINは、両方のテーブルに情報が揃っているものを確実に抽出できますが、一方のテーブルにしか情報がない行は結果から除外されてしまうという特性があります。

「ユーザー情報がなくても、注文があった事実はすべて一覧として表示したい!」という場合、INNER JOINの結果では「ブドウ」の注文情報がまるっと抜け落ちてしまうので困りますよね。

このように、「片方のテーブルに一致するデータがなくても、基準となるテーブルの行はすべて結果に残したい!」という場合に使うのが、外部結合(OUTER JOIN)です。


外部結合(OUTER JOIN)

OUTER JOIN(外部結合)は、「片方のテーブルには一致するデータがなくても、基準となるテーブルの情報はすべて結果に残して結合する」という方法です。

基準となるテーブルのデータはすべて結果に含まれ、結合相手が見つからない部分には NULL が入ります。

OUTER JOINの基本構文

外部結合の書き方はこちらの通りです。

SELECT * または 必要なカラム名
FROM テーブル1
LEFT(またはRIGHT) OUTER JOIN テーブル2
ON テーブル1.共通カラム = テーブル2.共通カラム;

INNER JOINとの違いは、主にINNER JOINの部分が LEFT OUTER JOIN または RIGHT OUTER JOIN になる点です。LEFT を使うか RIGHT を使うかで、「どちらのテーブルを基準として全行を残すか」が決まります。

ON句の役割はINNER JOINと全く同じで、「どのカラムの値が一致したら行同士をくっつけるか」という結合条件を指定します。


左外部結合(LEFT OUTER JOIN)

LEFT OUTER JOIN(左外部結合)は、2つのテーブルを結合する際に、「左側」に指定したテーブルの全ての行を必ず残すという特徴があります。右側のテーブルに対応するデータがない場合でも、左側のデータは結果に含まれます。

具体例

先ほどの例(ordersテーブルに user_id = 4 のデータがあるが、usersテーブルには存在しない状態)で、LEFT OUTER JOINを使ってみます。

SELECT *
FROM orders AS o          -- 左側のテーブル(基準)
LEFT OUTER JOIN users AS u  -- 右側のテーブルを左外部結合
ON o.user_id = u.user_id;  -- 結合条件

INNER JOINが LEFT OUTER JOIN に変わっただけですね!

実行結果:

order_id | user_id | product_name | user_id | name
--------------------------------------------------
101 | 1 | リンゴ | 1 | 佐藤太郎
102 | 2 | みかん | 2 | 鈴木次郎
103 | 1 | バナナ | 1 | 佐藤太郎
104 | 4 | ブドウ | NULL | NULL

INNER JOINでは消えてしまっていた「ブドウ」の注文が、ちゃんと結果に残っています!

ただし、user_id = 4 のユーザーはusersテーブルに存在しなかったので、usersテーブルから持ってくるはずだった user_id と name のカラムには NULL が入っています。

LEFT OUTER JOINを使うことで、「ユーザー情報がなくても、注文一覧はすべて表示したい」という目的を達成できました!

まとめると、左外部結合は「左側のテーブルを基準として、対応するデータが右側のテーブルにあれば結合し、なければNULLとしてでも左側のデータは必ず表示する」という結合方法です。


右外部結合(RIGHT OUTER JOIN)

RIGHT OUTER JOIN(右外部結合)は、左外部結合と考え方が似ていますが、基準となるテーブルが逆になります

右外部結合は、2つのテーブルを結合する際に、「右側」に指定したテーブルの全ての行を必ず残すという特徴があります。左側のテーブルに対応するデータがない場合でも、右側のデータは結果に含まれます。

具体例

左外部結合と同じ orders テーブルに加えて、usersテーブルに user_id = 100 の「田中四郎」さんを追加した状態で考えてみましょう。

usersテーブル(追加後)

user_id | name | 
-----------------
1 | 佐藤太郎 | 
2 | 鈴木次郎 | 
3 | 高橋三郎 | 
100 | 田中四郎 | ← 追加

これらのテーブルを user_id をキーとして右外部結合します。

SELECT *
FROM orders AS o            -- 左側のテーブル
RIGHT OUTER JOIN users AS u  -- 右側のテーブルを右外部結合(基準)
ON o.user_id = u.user_id;   -- 結合条件

RIGHT OUTER JOINによって users テーブルが右側(基準)となるため、usersテーブルの全行が結果のベースとなります。

実行結果:

order_id | user_id | product_name | user_id | name
--------------------------------------------------
101 | 1 | リンゴ | 1 | 佐藤太郎
102 | 2 | みかん | 2 | 鈴木次郎
103 | 1 | バナナ | 1 | 佐藤太郎
NULL | NULL | NULL | 100 | 田中四郎

基準となる右側の users テーブルのデータは4行とも全て出力されています。

user_id = 100 の「田中四郎」さんの行を見てください。usersテーブルにはデータがあるものの、ordersテーブルにはそのユーザーの注文がありません。そのため、結合されるはずだった orders テーブルのカラム(order_id・product_name)には NULL が入っています。

また、LEFT OUTER JOINの結果と異なり、ordersテーブルにあった order_id = 104 の「ブドウ」のデータは、基準である右側のusersテーブルに対応する user_id = 4 がないため、結果に含まれていません。

まとめると、右外部結合は「右側のテーブルを基準として、対応するデータが左側のテーブルにあれば結合し、なければNULLとしてでも右側のデータは必ず表示する」という結合方法です。

「LEFT」と「RIGHT」は少しわかりにくいかもしれませんが、SQL文を書いたときのテーブルの位置(JOINキーワードの左か右か)を指しているだけと考えるとシンプルです。


内部結合と外部結合のまとめ・使い分け

ここで、内部結合(INNER JOIN)と外部結合(LEFT OUTER JOIN・RIGHT OUTER JOIN)の特徴と違いを整理しましょう。

INNER JOIN(内部結合)
・特徴:両方のテーブルに一致するデータがある行だけを結合して結果に残す
・使いどころ:両テーブルに共通するデータだけを厳選して取得したい場合

LEFT OUTER JOIN(左外部結合)
・特徴:左側のテーブルの全行を残す。右側に対応データがなければNULL
・使いどころ:左側(FROM句)のテーブルの情報はすべて見たい場合

RIGHT OUTER JOIN(右外部結合)
・特徴:右側のテーブルの全行を残す。左側に対応データがなければNULL
・使いどころ:右側(OUTER JOIN句)のテーブルの情報はすべて見たい場合

使い分けのイメージ

INNER JOIN(内部結合)は、関連情報が両方のテーブルに確実に存在するデータだけを厳選して取得したい場合に使います。

OUTER JOIN(外部結合)は、「とにかく軸にしたテーブルの情報は全部見たい。それに関連するもう片方のテーブルの情報があれば表示し、なければNULLでも良い」という場合に使います。「LEFT」と「RIGHT」は、どちらのテーブルを軸(基準)にしたいかで選びます。


まとめ

今回は、SQLのテーブル結合(JOIN)について学びました。

  • テーブル結合(JOIN) とは、複数のテーブルを1つに「くっつける」操作で、共通のカラム(キー)の値が一致する行同士を結びつけます。

  • INNER JOIN(内部結合) は、両方のテーブルに一致するデータがある行だけを結果に残します。一致しないデータは除外されます。

  • LEFT OUTER JOIN(左外部結合) は、左側のテーブルの全行を基準にし、右側に一致するデータがなければNULLで補います。

  • RIGHT OUTER JOIN(右外部結合) は、右側のテーブルの全行を基準にし、左側に一致するデータがなければNULLで補います。

  • JOINを使う際のSELECT句では、テーブル名.カラム名 または エイリアス.カラム名 の形式で、どのテーブルのカラムかを明示することが重要です。

テーブル結合は、データベースから必要な情報を自由自在に引き出すための強力な武器です。実務では使わない日はないと言っても過言ではないくらい重要なテクニックですので、ぜひ実際に手を動かしてSQLを書いてみてください!


📺 この記事はYouTube動画でも解説しています

チャンネル登録もぜひよろしくお願いします!


🎓 Udemyコースで学ぼう

データベース分野を体系的に学ぶなら:
👉 【応用情報技術者試験】データベース分野・午前(科目A)完全攻略コース

セキュリティ分野の対策も忘れずに:
👉 応用情報技術者試験 午前コース(セキュリティ)

https://www.udemy.com/course/applied-information-technology-security-master-a/

👉 応用情報技術者試験 午後コース(セキュリティ)

https://www.udemy.com/course/applied-information-technology-security-master-b/


🚀 AIに「なぜ?」を聞ける過去問アプリ「Tokeru」を開発中です

過去問を解いて終わりにせず、間違えた問題の「なぜ」をAIに聞いて、弱点を狙って復習できる学習アプリを開発しています。

8月29日(土)に先行公開予定です。先行公開の期間は、全年度の過去問も模擬試験もすべて無料で使えます。

👉 【8/29(土)先行公開】Tokeruはこちら


いいなと思ったら応援しよう!