コマンド道場

INNER JOIN(内部結合)の使い方

ひとことで言うと

juchu受注

juchu_idkokyaku_id
10011
10022

kokyaku顧客

kokyaku_idkokyaku_name
1青葉工業
2白樺物産
5三田商事

INNER JOINつないだ結果

juchu_idkokyaku_idkokyaku_name
10011青葉工業
10022白樺物産
  • kokyaku_nameのように、右の表の列が左の表にくっつくのが結合です。
  • 受注 10 行 → つないだ結果 10(行数は変わりません)
  • 取り消し線= 相手がいないので結果に出てこない行
  • 受注側に取り消し線が無いのは、必ず顧客に紐づいているためです。

INNER JOIN は、2 つの表の「対応する行どうし」をつなぐ書き方です。 対応する相手がいない行は結果に出てきません。この「出てこない」性質が、便利さと事故の両方の原因になります。

主要 7 製品で通用 そのまま使える: PostgreSQL / MySQL / MariaDB / SQLite / SQL Server / Oracle Database / IBM Db2

製品ごとの対応表(実測)を見る

このページの実行結果と図は、すべて本物のデータベースに同じ SQL を流して得たものです。手で書いた「たぶんこうなる」ではありません。

01なぜ結合が必要なのか

受注の表には、顧客が kokyaku_id という番号でしか入っていません。表を分けて番号で参照し合うのは、顧客名が変わったときに 1 か所だけ直せば済むようにするためです。

しかし画面や帳票に出したいのは番号ではなく顧客名です。この「番号から名前を引き当てる」操作が結合(JOIN)です。

まず受注表そのものを見てみます。kokyaku_id はあっても顧客名はどこにもありません。

受注表(juchu)
SELECT juchu_id, kokyaku_id, juchu_on, status
FROM juchu
ORDER BY juchu_id;
juchu_idkokyaku_idjuchu_onstatus
100112025-11-05done
100222025-11-18done
100312025-12-02done
100432025-12-09cancel
100542025-12-24done

10 … うち先頭 5 行を表示

02基本形は FROM … JOIN … ON

結論: `FROM 表A JOIN 表B ON 表A.列 = 表B.列` と書きます。

ON に書くのは「どの列どうしが同じものを指しているか」です。ここでは受注表の kokyaku_id と顧客表の kokyaku_id が同じ顧客を指しているので、それを等号で結びます。

juchu jj別名(エイリアス)です。どの表の列かを毎回フルネームで書くと長くなるので、短い名前を付けています。付けなくても動きますが、表が増えるほど読みづらくなるので最初から付ける習慣にしてください。

1 行ずつ、何をしているか
  1. SELECT j.juchu_id, k.kokyaku_name何を出すか
  2. FROM juchu j主となる表(別名 j)
  3. JOIN kokyaku kつなぐ相手(別名 k)
  4. ON k.kokyaku_id = j.kokyaku_idどの列どうしが同じか
  5. ORDER BY j.juchu_id並び順

上から順に読むのではなく、FROM と JOIN で「どの表を見るか」を決め、ON で「どうつなぐか」を決め、SELECT で「何を出すか」を選ぶ、という関係です。

受注に顧客名をつなぐ
SELECT j.juchu_id, k.kokyaku_name, j.juchu_on
FROM juchu j
JOIN kokyaku k ON k.kokyaku_id = j.kokyaku_id
ORDER BY j.juchu_id;
juchu_idkokyaku_namejuchu_on
1001青葉工業2025-11-05
1002白樺物産2025-11-18
1003青葉工業2025-12-02
1004黒松システム2025-12-09
1005赤坂商会2025-12-24

10 … うち先頭 5 行を表示

03INNER は省略できる

JOIN とだけ書くと INNER JOIN の意味になります。どちらで書いても結果は同じです。

読み手に親切なのは明示する方ですが、実務では省略形もよく使われます。大事なのは同じ文の中で書き方を混ぜないことです。

INNER を明示しても結果は変わらない
SELECT j.juchu_id, k.kokyaku_name
FROM juchu j
INNER JOIN kokyaku k ON k.kokyaku_id = j.kokyaku_id
ORDER BY j.juchu_id;
juchu_idkokyaku_name
1001青葉工業
1002白樺物産
1003青葉工業

10 … うち先頭 3 行を表示

04内部結合は「相手がいない行」を落とす

ここが内部結合でいちばん重要な性質です。

このデータには顧客が 5 社いますが、受注が 1 件も無い会社が 1 社あります。内部結合すると、その会社は結果から消えます。エラーにも警告にもなりません。黙って消えます。

「顧客の一覧を出したら 1 社足りない」「合計は合っているのに件数が合わない」という不具合は、たいていこれが原因です。

消したくない場合は外部結合(LEFT OUTER JOIN)を使います。

どの行がどの行につながるか
受注 juchu顧客 kokyaku1001kokyaku_id=11002kokyaku_id=21004kokyaku_id=31005kokyaku_id=41青葉工業2白樺物産3黒松システム4赤坂商会5三田商事

ON k.kokyaku_id = j.kokyaku_id

左は顧客ごとに代表 1 件だけ載せています。右は全 5 社です。線が引かれていない行(点線・✕)は、内部結合の結果に出てきません。

① 顧客表そのもの
SELECT kokyaku_id, kokyaku_name
FROM kokyaku
ORDER BY kokyaku_id;
kokyaku_idkokyaku_name
1青葉工業
2白樺物産
3黒松システム
4赤坂商会
5三田商事

5

② 受注と内部結合したあと(1 社消えている)
SELECT DISTINCT k.kokyaku_id, k.kokyaku_name
FROM kokyaku k
JOIN juchu j ON j.kokyaku_id = k.kokyaku_id
ORDER BY k.kokyaku_id;
kokyaku_idkokyaku_name
1青葉工業
2白樺物産
3黒松システム
4赤坂商会

4

①と②を見比べてください。三田商事(kokyaku_id = 5)が抜けています。受注が 1 件も無いためです。エラーも警告も出ません。

05⚠️ よくある間違い:ON を書き忘れると件数が爆発する

FROM juchu, kokyaku のようにカンマで並べただけで結合条件を書かないと、すべての組み合わせが返ります。これをクロス結合(直積)といいます。

ここでは受注 10 行 × 顧客 5 行 = 50 行。数が小さいので気づけますが、実務の表は数万行あります。数万 × 数万は数十億行で、返ってくる前にサーバーが悲鳴を上げます。

「結果の件数が想定よりやたら多い」ときは、まず結合条件の書き忘れを疑ってください。

欲しいのは緑のマスだけ
受注 10

顧客 5

本当に欲しい組み合わせ
10 通り
ON を書かないと返ってくる
50 通り

1 行につき正しい相手は 1 つだけ。ON を書かないと、その行以外の赤いマスも全部返ってきます。

結合条件を書かないと 50 行になる
SELECT count(*) AS kensu
FROM juchu, kokyaku;
kensu
50

1

中身を見ると、同じ受注に全顧客がぶら下がっている
SELECT j.juchu_id, k.kokyaku_name
FROM juchu j, kokyaku k
ORDER BY j.juchu_id, k.kokyaku_id;
juchu_idkokyaku_name
1001青葉工業
1001白樺物産
1001黒松システム
1001赤坂商会
1001三田商事
1002青葉工業

50 … うち先頭 6 行を表示

受注 1001 に 5 社ぜんぶが結び付いています。正しいのはこのうち 1 行だけです。

06⚠️ よくある間違い:同じ名前の列は、どちらの表か指定しないとエラーになる

両方の表に kokyaku_id があるとき、kokyaku_id とだけ書くとデータベースはどちらか判断できません。あいまい(ambiguous)というエラーになります。

直し方は簡単で、j.kokyaku_id のように表名(または別名)を前に付けるだけです。

このエラーは初心者がいちばん多く出会うものですが、メッセージが原因をそのまま言ってくれているので、読めばすぐ直せます。

わざとエラーになる例
SELECT kokyaku_id, kokyaku_name
FROM juchu
JOIN kokyaku ON kokyaku.kokyaku_id = juchu.kokyaku_id;
ERROR: column reference "kokyaku_id" is ambiguous

先頭の kokyaku_id が juchu のものか kokyaku のものか決まらないため。

07列名が同じなら USING でも書ける

つなぐ列の名前が両方の表でまったく同じときに限り、ON k.kokyaku_id = j.kokyaku_id`USING (kokyaku_id)` と短く書けます。

USING を使うと、結合列は 1 本にまとめられます(SELECT * したときに kokyaku_id が 2 回出てこない)。

ただし使えない製品があります。迷ったら ON を選んでください。ON は調べたすべての製品で通ります。

USING で書いた場合
SELECT j.juchu_id, k.kokyaku_name
FROM juchu j
JOIN kokyaku k USING (kokyaku_id)
ORDER BY j.juchu_id;
juchu_idkokyaku_name
1001青葉工業
1002白樺物産
1003青葉工業
1004黒松システム

10 … うち先頭 4 行を表示

⚠️ この書き方は SQL Server では使えません(JOIN ... USING (列))。製品ごとの対応表

083 つ以上の表をつなぐ

JOIN は続けて書けます。読み方は「左から順に、ここまでつないだ結果に次の表をつないでいく」です。

受注(juchu)→ 明細(juchu_meisai)→ 商品(shohin)とたどると、「どの受注で・何を・いくつ買ったか」が 1 枚の表になります。

表が増えても考え方は同じで、それぞれの `JOIN` に対応する `ON` を 1 つずつ書くだけです。JOIN が 2 つあるのに ON が 1 つしかなければ、そこで件数が爆発します。

たどる順番
  1. juchu受注
    juchu_id
  2. juchu_meisai明細
    shohin_id
  3. shohin商品

矢印に書いてあるのが、その JOIN の ON で使う列です。

受注 × 明細 × 商品
SELECT j.juchu_id, s.shohin_name, m.suryo, m.tanka
FROM juchu j
JOIN juchu_meisai m ON m.juchu_id = j.juchu_id
JOIN shohin s ON s.shohin_id = m.shohin_id
WHERE j.status = 'done'
ORDER BY j.juchu_id, m.gyo_no;
juchu_idshohin_namesuryotanka
1001ノート20180
1001ボールペン30120
1002デスクチェア223800
1002書棚118500
1003デスクライト44200
1003キーボード28900
1005ノート10180
1005ボールペン0120

15 … うち先頭 8 行を表示

自分で打ってみる

このページの例と同じデータが入った本物のデータベースを、この場(あなたのブラウザの中)で起動できます。打った SQL がサーバーへ送られることはありません。

押すと初回だけ約 9MB を読み込みます(2 回目以降はキャッシュされます)。

解いてみる

読んだだけでは書けるようになりません。実行結果で採点します。

関連するトピック

  • LEFT / RIGHT OUTER JOIN内部結合で消えてしまう行を残したいときに使います。
  • ON 句と USING 句ON と USING の違い、結合条件と絞り込み条件の使い分け。
  • CROSS JOINON を書き忘れたときに起きるのが、これを明示的に書いた状態です。

根拠(一次情報)