はじめに
SQLを学び始めて、最初に「おや?」と疑問に思うポイントがありました。それは、以下のような INNER JOIN(内部結合)のクエリを見たときです。
SELECT
orders.order_id
,customers.customer_name -- ← FROMの後ろにないマスタテーブルの列?!
FROM
orders
INNER JOIN
customers
ON
orders.customer_id = customers.customer_id
FROM orders と書かれているので、一見すると注文履歴テーブル(orders)だけからデータを取っているように見えます。それなのに、なぜ SELECT 句に別のテーブル(customers)の列を書いてもエラーにならず、正しいデータが取得できるのでしょうか?
本記事の対象読者
- SQLの入門書を読み進めているけれど、JOINの内部的な動きがいまいちピンと来ていない方
-
FROMに書いたテーブル以外の列をSELECTできる仕組みが不思議で夜も眠れない方 - データベースが裏側でどのようにデータを「お取り寄せ」しているのか、イメージで理解したい方
今回は、データベースのメモリの中で起きているデータ合体のメカニズムを、解説します!
1. JOINするとメモリの中に何が起きる? 「合体シート」の秘密
結論から言うと、INNER JOIN を実行した瞬間、データベースのメモリの中には2つのテーブルのカラム(列)がすべて横一列に並んだ「1つの巨大な合体一時シート」が作られています。
例えば、以下のような2つの一般的なテーブルがあるとします。
- 左テーブル(出発点):
orders(カラム:order_id,order_date,customer_id) - 右テーブル(合体相手):
customers(カラム:customer_id,customer_name,email)
この2つを、共通する customer_id(顧客ID)が同じものという条件で INNER JOIN させると、データベースのメモリの中には、次のような 6つのカラムがすべて並んだ1枚の大きな表 が一時的に出来上がります。
【合体した中間テーブルのイメージ】
| 元ordersの列:order_id | 元ordersの列:order_date | 元ordersの列:customer_id | 元customersの列:customer_id | 元customersの列:customer_name | 元customersの列:email |
|---|---|---|---|---|---|
| 10001 | 2026/06/29 | C001 | C001 | 山田太郎 | yamada@example.com |
結合が終わったこの瞬間、データベースにとっては、これは2つの別々のテーブルではなく、すべての値が揃った「1つのシート」として見えています。
この合体シートの上には、当然 customer_name や email も並んでいます。
だからこそ、SELECT句で「この合体シートから『元customers側にある列』を切り取って持ってきて!」と書けば、何の問題もなく2つのテーブルの値を同時に取り出すことができるのです。
2. SQLの文法トリック:なぜ FROM の後ろには1つしか書かないの?
「両方のテーブルからデータを取るなら、FROM orders, customers って書けばいいのに」と思うかもしれません。
SQLの文法(ルール)では、「まずベース(出発点)となるテーブルを1つ決めて、そこに別のテーブルを右にくっつけていく」という書き方をすることになっています。
FROM
orders -- ① まずはこいつを出発点のベースにするよ!
INNER JOIN
customers -- ② そこに、こいつを右側にくっつけてね!
この「出発点」と「合体相手」を書き並べた時点で、データベース側は「よし、この2つをくっつけた合体シートを作ればいいんだな」と理解します。
そのため、FROM の直後には1つのテーブル名しか見えませんが、その後に INNER JOIN が続いているため、データベースにとっては「両方のテーブルのすべての情報が載ったシート」を扱っている状態になるのです。
3. SQL実行の「3つのステップ」(お取り寄せの流れ)
データベースがSQLを実行するとき、頭から順番に処理しているわけではありません。実は、裏側では以下の「3つのステップ」でデータをふるいにかけてお取り寄せしています。
【ステップ①】結合(JOIN):横に広げて合体シートを作る
まずはベースとなるテーブルに、相手のテーブルを右側にくっつけて、すべての列が並んだ一時テーブル(合体シート)をメモリ上に作ります。
【ステップ②】抽出(WHERE):条件に合わない「行(横)」を消す
次に、できあがった合体シートに対して、例えば WHERE orders.order_date >= '2026/06/01'(6月以降の注文だけ)といった条件を使い、条件に合わない「行(横一行のデータ)」をゴミ箱にポイポイ捨てていきます。
これによって、条件をクリアした「エリートな行」だけがシートに残ります。
【ステップ③】選択(SELECT):必要な「列(縦)」だけ切り抜く
最後に、ふるいに残った綺麗なシートから、SELECT 句で指定された「特定の列(縦の項目)」だけを切り抜きます。
今回の例で言えば、最終的に orders.order_id と customers.customer_name の2つだけを切り抜いて、私たちの画面(またはプログラム)に返却してくれます。
どれだけ合体シートが横に長くても、最後に必要な列だけを切り抜くから、無駄なくスマートにデータが取得できるのです。
さいごに
SQLのクエリを文字だけで見ていると、FROM にあるテーブルに縛られてしまいがちですが、「JOINした時点で、裏側では2つのテーブルが1つになった巨大な合体シートができている」というイメージを持つと、SQLの視界が変わるかと思います。
このイメージを持つことで、テーブルが3つ、4つと増えて複雑な結合が登場しても、「右側にどんどんくっつけて、シートを広げているんだな」「最後にSELECTで縦に切り抜いているんだな」と、迷子にならずにロジックを読めるようになります。
SQLの勉強、最初は覚える構文が多くて大変かもしれませんが、イメージで捉えると一気に楽しくなりますよ。一歩ずつ、データベースの操作を楽しんでいきましょう!