PostgreSQLのJOIN(結合)初心者ガイド!INNER・LEFT・RIGHT JOINとON句の使い方を完全解説
生徒
「PostgreSQLを勉強し始めたのですが、JOIN(ジョイン)という言葉が出てきて混乱しています。複数の表をくっつけるってどういうことですか?」
先生
「JOINは、別々に保存されている『名簿の表』と『注文の表』などを、共通の目印を使って一つの大きな表に合体させる魔法のような命令ですよ。」
生徒
「共通の目印……。なんだか難しそうですね。ON句というのもセットで覚えないといけないんですか?」
先生
「その通りです!ON句は『どの列とどの列を基準にして合体させるか』を決める接着剤の役割をします。これさえマスターすれば、データベースから自由自在にデータを取り出せるようになりますよ。」
1. データベースの「結合(JOIN)」とは?
データベースを扱う上で、最も重要で便利な機能の一つが「JOIN(結合)」です。PostgreSQL(ポストグレスキューエル)などのデータベース管理システムでは、データを一つの巨大な表に詰め込むのではなく、種類ごとに分けて保存するのが基本です。
例えば、「お客様の情報(名前や住所)」と「お買い物の履歴(いつ何を買ったか)」を一つの表にまとめると、同じお客様が何度も買い物をするたびに名前や住所を何度も書き直す必要があり、非常に効率が悪くなります。そこで、普段は「お客様の表」と「お買い物の表」を別々に用意しておき、必要なときだけこの二つをくっつけて表示させるのです。この「くっつける作業」のことをJOINと呼びます。
パソコンを触ったことがない方でも、パズルのピースを合わせる様子をイメージしてみてください。二つのピースには、必ず「ここが合わさる部分」という凹凸がありますよね。SQLにおけるJOINも、二つの表の中にある共通のデータ(例えば会員IDなど)を頼りにして、表をガッチャンコとつなぎ合わせるのです。
2. 表を繋ぐ魔法の言葉「ON句」の役割
表と表を結合するときに、必ずセットで使うのが「ON(オン)句」です。これは、コンピュータに対して「この列とこの列が一致するもの同士を隣り合わせにしてね」という指示を出すためのものです。
例えば、クラス名簿(生徒ID、名前)と、テスト結果(生徒ID、点数)という二つの表があるとします。この二つの表を繋げたいとき、「生徒ID」が同じであれば、それは同じ人物のデータだと分かりますよね。このとき、SQLでは「ON 名簿の生徒ID = テスト結果の生徒ID」という書き方をします。これがON句の役割です。この指示がないと、コンピュータはどのデータとどのデータを組み合わせればいいのか分からず、めちゃくちゃな結果になってしまいます。
3. 共通部分だけを抽出!INNER JOIN(内部結合)の使い方
まずは一番基本となる「INNER JOIN(内部結合)」について解説します。これは、二つの表の両方に存在するデータだけを表示する方法です。どちらか片方の表にしかデータがない場合は、結果には表示されません。
例えば、「商品名リスト」と「在庫リスト」を結合する場合、商品名はあるけれど在庫情報が登録されていないものは表示されません。逆に、在庫情報はあるけれど商品名が登録されていないものも表示されません。両方の表にバッチリ揃っているデータだけをきれいに抜き出します。
【結合前のテーブル:students(生徒)】
id | name | class_id
---+----------+---------
1 | 田中太郎 | 10
2 | 佐藤花子 | 10
3 | 鈴木一郎 | 20
4 | 高橋良子 | 99
【結合前のテーブル:classes(クラス)】
id | class_name
---+------------
10 | Aクラス
20 | Bクラス
30 | Cクラス
それでは、INNER JOINを使って「生徒名」と「クラス名」をセットで表示してみましょう。
SELECT students.name, classes.class_name
FROM students
INNER JOIN classes
ON students.class_id = classes.id;
【実行結果】
name | class_name
----------+------------
田中太郎 | Aクラス
佐藤花子 | Aクラス
鈴木一郎 | Bクラス
※高橋良子さんはclass_idが「99」で、classes表に「99」が存在しないため表示されません。また、Cクラスも所属する生徒がいないため表示されません。
4. 左側を優先する LEFT JOIN(左外部結合)
次に紹介するのは「LEFT JOIN(レフトジョイン)」です。これは、結合の「左側(先に書いた方)」の表にあるデータをすべて表示し、右側の表にデータがあればそれをくっつける、という方法です。もし右側の表に一致するデータがなければ、その部分は「空っぽ(NULLといいます)」として表示されます。
初心者の方向けに言い換えると、「左側の表は絶対全員分出すから、右側の表に情報があればついでに出してね」という指示です。先ほどの生徒名簿の例で言うと、「クラスが決まっていない生徒も、名簿からは消さずに表示したい」という場合に役立ちます。
【結合前のテーブル:students(生徒)】
id | name | class_id
---+----------+---------
1 | 田中太郎 | 10
2 | 佐藤花子 | 10
3 | 鈴木一郎 | 20
4 | 高橋良子 | 99
【結合前のテーブル:classes(クラス)】
id | class_name
---+------------
10 | Aクラス
20 | Bクラス
30 | Cクラス
SELECT students.name, classes.class_name
FROM students
LEFT JOIN classes
ON students.class_id = classes.id;
【実行結果】
name | class_name
----------+------------
田中太郎 | Aクラス
佐藤花子 | Aクラス
鈴木一郎 | Bクラス
高橋良子 | (null)
このように、右側のクラス表にデータがない「高橋さん」も、LEFT JOINを使えば無視されずに表示されます。クラス名は「わからない(null)」となります。これがLEFT JOINの優しさです。
5. 右側を優先する RIGHT JOIN(右外部結合)
RIGHT JOIN(ライトジョイン)は、LEFT JOINの逆です。結合の「右側(後に書いた方)」の表にあるデータをすべて表示します。左側の表に一致するデータがなくても、右側のデータは必ず残ります。
「生徒が一人もいないクラスも含めて、すべてのクラス一覧と、そこに所属する生徒を表示したい」という時はRIGHT JOINが便利です。ただ、実際の開発現場では表を書く順番を入れ替えてLEFT JOINで済ませることが多いため、RIGHT JOINはあまり頻繁には見かけませんが、仕組みを理解しておくことは非常に大切です。
【結合前のテーブル:students(生徒)】
id | name | class_id
---+----------+---------
1 | 田中太郎 | 10
2 | 佐藤花子 | 10
3 | 鈴木一郎 | 20
【結合前のテーブル:classes(クラス)】
id | class_name
---+------------
10 | Aクラス
20 | Bクラス
30 | Cクラス
SELECT students.name, classes.class_name
FROM students
RIGHT JOIN classes
ON students.class_id = classes.id;
【実行結果】
name | class_name
----------+------------
田中太郎 | Aクラス
佐藤花子 | Aクラス
鈴木一郎 | Bクラス
(null) | Cクラス
今度は「Cクラス」が表示されましたね!生徒名簿にはCクラスの人がいないので名前は「(null)」になっていますが、クラス側のデータが優先された結果です。
6. 用語解説:NULL(ヌル)とエイリアス(別名)
ここで少し難しい言葉の整理をしましょう。プログラミングやSQLの世界では、データが入っていない状態のことを「NULL(ヌル)」と呼びます。これは「0(ゼロ)」や「空欄」とは少し違い、「そこには何も存在しない」「不明である」という意味を持ちます。JOINを使うと、このNULLという文字を目にすることが増えますが、慌てなくて大丈夫です。
また、SQLを書くときにテーブル名が長いと何度も書くのが大変ですよね。そんなときは「エイリアス(別名)」を使うことができます。例えば `FROM students AS s` と書くと、それ以降は `students` と書かずに `s` と書くだけでよくなります。これは「あだ名」をつけるようなものだと考えてください。コードがスッキリして読みやすくなります。
7. 実践的なON句のテクニック:複数の条件で繋ぐ
ON句には、一つの条件だけでなく、複数の条件を指定することもできます。例えば「日付と店舗IDの両方が一致する場合だけ結合したい」といった高度な使い方も可能です。その場合は「AND」という言葉を使って条件を繋ぎます。
「このお店の、この日に来たお客様だけを表示する」といった複雑な絞り込みも、ON句を使いこなすことで可能になります。初心者の方は、まずは「ON A.ID = B.ID」という一つの条件から慣れていき、徐々に複雑な結合にチャレンジしてみましょう。
【結合前のテーブル:sales(売上)】
id | shop_id | sale_date | amount
---+---------+------------+-------
1 | 101 | 2026-01-01 | 500
2 | 101 | 2026-01-02 | 800
3 | 102 | 2026-01-01 | 300
【結合前のテーブル:campaigns(キャンペーン)】
shop_id | campaign_date | campaign_name
--------+---------------+--------------
101 | 2026-01-01 | お正月セール
102 | 2026-01-01 | 開店記念
SELECT s.sale_date, s.amount, c.campaign_name
FROM sales AS s
INNER JOIN campaigns AS c
ON s.shop_id = c.shop_id AND s.sale_date = c.campaign_date;
【実行結果】
sale_date | amount | campaign_name
-----------+--------+--------------
2026-01-01 | 500 | お正月セール
2026-01-01 | 300 | 開店記念
この例では、店舗IDと日付の両方が一致した時だけ、キャンペーン名を表示しています。1月2日の売上は、キャンペーンがない日なので表示されません。このように、ON句は非常に精密なコントロールができるのです。
8. データベース操作のコツ:まずはSELECT * から始めよう
初心者の人がJOINを練習するときは、最初から特定の列だけを選ぼうとすると混乱しがちです。まずは `SELECT *`(セレクト・すべて)を使って、結合された後の大きな表の全体像を見てみるのが上達への近道です。
全体を見て、「あ、こことここが繋がっているんだな」と納得してから、必要な列(名前や日付など)に絞り込んでいくようにしましょう。PostgreSQLは非常に素直なシステムなので、あなたが書いたON句の通りに忠実にデータを並べてくれます。エラーが出ても、それは「パズルの形が合っていないよ」というヒントなので、焦らずに表の列名を見直してみてください。
9. なぜPostgreSQLでJOINを学ぶのがいいの?
世界中で使われているPostgreSQLは、非常に多機能で安定したデータベースです。ここで学んだJOINやON句の知識は、MySQLやOracle、SQL Serverといった他のデータベースでもほとんどそのまま使えます。つまり、一度覚えてしまえば一生モノのスキルになるのです。
また、最近ではAIやデータ分析の分野でも、この「表を結合する」という作業は欠かせません。バラバラになった膨大なデータから、意味のある情報を引き出すための第一歩がJOINなのです。最初は少しややこしく感じるかもしれませんが、紙に図を書いて整理してみると、意外とシンプルなルールで動いていることが分かりますよ。
まとめ
PostgreSQLにおけるJOIN(結合)は、バラバラに管理されているテーブルを一つの意味あるデータセットとして統合するための非常に強力なツールです。本記事では、データベースの設計思想である「正規化」によって分かれたテーブルを、共通の鍵(IDなど)を頼りに再構築する方法を詳しく解説してきました。
特に重要なポイントを振り返ると、まずINNER JOIN(内部結合)は、両方のテーブルに共通して存在するデータのみを抽出する、最も厳密な結合方法です。これに対してLEFT JOIN(左外部結合)は、主となる左側のテーブルの情報を一切漏らすことなく、関連する情報を右側から補完する際に非常に便利です。また、RIGHT JOIN(右外部結合)はその逆の性質を持ちますが、実務上はテーブルの記述順序を入れ替えてLEFT JOINで対応することが一般的であることも学びました。
結合の際の「接着剤」となるON句の役割も忘れてはいけません。どの列とどの列をマッチングさせるかを明示することで、データベースは正確に計算を行うことができます。さらに、AS(エイリアス)を活用したコードの簡略化や、複数の条件(AND)を用いた複雑な結合など、実務で即戦力となるテクニックも紹介しました。
データベース運用のためのSQL実践例
ここで、これまでの知識を総括するために、より具体的なビジネスシーンを想定した「注文管理システム」のデータ結合をシミュレーションしてみましょう。顧客テーブル(customers)と注文テーブル(orders)を使い、未注文の顧客も含めた全リストを出力する方法を確認します。
【結合前のテーブル:customers(顧客)】
id | customer_name | region
---+---------------+-------
1 | 佐藤健太 | 東京
2 | 鈴木美咲 | 大阪
3 | 高橋裕二 | 福岡
4 | 伊藤あずさ | 北海道
5 | 渡辺直樹 | 名古屋
【結合前のテーブル:orders(注文履歴)】
order_id | customer_id | product_name | price
---------+-------------+--------------+------
101 | 1 | キーボード | 5000
102 | 1 | マウス | 3000
103 | 3 | モニター | 25000
104 | 5 | USBメモリ | 1500
このデータを用いて、「誰が何を買ったか」を一覧にします。まだ購入履歴がない顧客(鈴木さんや伊藤さん)もリストに残したい場合は、LEFT JOINを使用します。
SELECT
c.customer_name,
c.region,
o.product_name,
o.price
FROM customers AS c
LEFT JOIN orders AS o
ON c.id = o.customer_id
ORDER BY c.id ASC;
【実行結果】
customer_name | region | product_name | price
--------------+----------+--------------+-------
佐藤健太 | 東京 | キーボード | 5000
佐藤健太 | 東京 | マウス | 3000
鈴木美咲 | 大阪 | (null) | (null)
高橋裕二 | 福岡 | モニター | 25000
伊藤あずさ | 北海道 | (null) | (null)
渡辺直樹 | 名古屋 | USBメモリ | 1500
このように、LEFT JOINを使用することで、顧客基盤(customers)をベースにしながら、購入経験のある人にはその詳細を、ない人にはNULLを表示させることができました。これにより、「どの地域の顧客がまだ購入に至っていないか」といったマーケティング分析も容易になります。
PostgreSQLを使いこなすことは、データの海から必要な真実を掬い上げる技術を身につけることです。JOINはその中でも最も頻繁に使われる手法ですので、何度もコードを書いて、その挙動を体で覚えていきましょう。SQLの基本をマスターすれば、データ分析やWebアプリケーション開発の幅が劇的に広がります。
生徒
「先生、JOINの使い分けがやっと腑に落ちました!『基本はINNER JOINで、漏らしたくないデータがあるときはLEFT JOIN』と考えればいいんですね。」
先生
「その通り、素晴らしい理解です!特に実務では、顧客リストや商品マスターなど『親となるテーブル』の情報をすべて出したい場面が多いので、LEFT JOINは本当によく使いますよ。」
生徒
「先ほどの実行結果で(null)が出たときも、エラーじゃなくて『データがないという状態』だとわかっていたので落ち着いていられました。エイリアス(AS)を使うとSQL文が短くなって、読みやすくなるのも感動です。」
先生
「いいところに気づきましたね。コードの可読性はチーム開発でも自分自身のミス防止にも役立ちます。あと、ON句で『c.id = o.customer_id』のように、違う名前の列同士でも中身のデータ(ID)が一致していれば結合できるという点も覚えておいてくださいね。」
生徒
「なるほど!列名が完全に同じじゃなくてもいいんですね。パズルのピースの色が違っても、形(値)が合えばつながるイメージですね。もっと複雑な条件にも挑戦してみたくなりました!」
先生
「その意気です。もし結合がうまくいかないときは、一度 SELECT * で結合後の全データを眺めてみると、どこでミスマッチが起きているかすぐに分かりますよ。次は複数のテーブルを3つ、4つと繋げる『多重結合』にも挑戦してみましょう!」