コマンド道場

ON 句と USING 句の使い方

ひとことで言うと

juchu受注

juchu_idkokyaku_id
10011
10022

kokyaku顧客

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

ONつないだ結果

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

ON に書くのは「この列とこの列が同じ行を指している」という対応関係です。絞り込みの条件ではありません。

`ON` は「どの行とどの行をつなぐか」を決める場所です。 WHERE(つないだ結果から何を残すか)とは役割も評価される順番も違います。内部結合では結果が同じになることが多いのですが、外部結合では答えが変わります

この書き方が使えない製品があります そのまま使える: PostgreSQL / MySQL / MariaDB / SQLite / Oracle Database / IBM Db2

  • SQL Server では使えませんJOIN ... USING (列)

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

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

01ON に書くのは「対応関係」

結論: `ON` には「どの列どうしが同じものを指すか」を書きます。

たいていは外部キーと主キーの対応、つまり ON 子.親id = 親.id の形になります。等号 1 つで足りることがほとんどです。

複数の列で対応させる場合は AND でつなぎます。受注番号と行番号のように、組み合わせで 1 行が決まる表を結合するときに使います。

1 行ずつ、何をしているか
  1. SELECT j.juchu_id, s.shohin_name, m.suryo何を出すか
  2. FROM juchu j主となる表
  3. JOIN juchu_meisai mつなぐ相手(1)
  4. ON m.juchu_id = j.juchu_id対応関係(1)
  5. JOIN shohin sつなぐ相手(2)
  6. ON s.shohin_id = m.shohin_id対応関係(2)
  7. ORDER BY j.juchu_id, m.gyo_no並び順

JOIN が 2 つあれば ON も 2 つ。1 つでも欠けると、その分だけ総当たりになります。

3 つの表をつなぐ
SELECT j.juchu_id, s.shohin_name, m.suryo
FROM juchu j
JOIN juchu_meisai m ON m.juchu_id = j.juchu_id
JOIN shohin s ON s.shohin_id = m.shohin_id
ORDER BY j.juchu_id, m.gyo_no;
juchu_idshohin_namesuryo
1001ノート20
1001ボールペン30
1002デスクチェア2
1002書棚1
1003デスクライト4
1003キーボード2

17 … うち先頭 6 行を表示

02内部結合なら ON と WHERE の結果は同じ

内部結合では、絞り込みの条件を ON に書いても WHERE に書いても同じ結果になります。

対応が無い行はどのみち消えるので、「つなぐ前に落とす」のと「つないだ後に落とす」のとで差が出ないからです。

この経験があるために、外部結合でも同じだと思い込むのが次の節の事故につながります。

① 条件を ON に書いた場合
SELECT j.juchu_id, k.kokyaku_name
FROM juchu j
JOIN kokyaku k ON k.kokyaku_id = j.kokyaku_id AND j.status = 'done'
ORDER BY j.juchu_id;
juchu_idkokyaku_name
1001青葉工業
1002白樺物産
1003青葉工業
1005赤坂商会

8 … うち先頭 4 行を表示

② 条件を WHERE に書いた場合(①と同じ結果)
SELECT j.juchu_id, k.kokyaku_name
FROM juchu j
JOIN kokyaku k ON k.kokyaku_id = j.kokyaku_id
WHERE j.status = 'done'
ORDER BY j.juchu_id;
juchu_idkokyaku_name
1001青葉工業
1002白樺物産
1003青葉工業
1005赤坂商会

8 … うち先頭 4 行を表示

03⚠️ よくある間違い:外部結合では ON と WHERE で答えが変わる

ここが本題です。 外部結合では、同じ条件を ON に書くか WHERE に書くかで結果が変わります。

  • `ON` に書く … 条件に合わない相手は「つながなかった」ことになる。左の行は残る(相手側が NULL
  • `WHERE` に書く … つないだ後で行ごと落とす。左の行が消える

WHERE に書くと、せっかく外部結合にした意味が無くなり、実質内部結合と同じになります。

判断の仕方: その条件が「つなぐ相手を選ぶ条件」なら ON、「最終的に残す行を選ぶ条件」なら WHERE です。

WHERE に書いた場合(受注が無い顧客が消える)
SELECT k.kokyaku_name, j.juchu_id, j.status
FROM kokyaku k
LEFT JOIN juchu j ON j.kokyaku_id = k.kokyaku_id
WHERE j.status = 'done'
ORDER BY k.kokyaku_id;
kokyaku_namejuchu_idstatus
青葉工業1008done
青葉工業1003done
青葉工業1001done
白樺物産1006done
白樺物産1002done

8 … うち先頭 5 行を表示

外部結合にしたのに、受注が 1 件も無い顧客が結果に出てきません。

ON に書いた場合(全顧客が残る)
SELECT k.kokyaku_name, j.juchu_id, j.status
FROM kokyaku k
LEFT JOIN juchu j ON j.kokyaku_id = k.kokyaku_id AND j.status = 'done'
ORDER BY k.kokyaku_id;
kokyaku_namejuchu_idstatus
青葉工業1008done
青葉工業1001done
青葉工業1003done
白樺物産1006done
白樺物産1002done

9 … うち先頭 5 行を表示

受注が無い顧客も残り、受注側の列が NULL になっています。顧客の一覧としてはこちらが正しい形です。

04列名が同じなら USING で短く書ける

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

USING を使うと結合列は 1 本にまとまるので、SELECT * したときに同じ列が 2 回出てきません。列名を表名で修飾する必要もなくなります。

ただし使えない製品があります(実測では SQL Server が非対応)。また、名前がたまたま同じだけの列を誤ってつないでしまう危険もあります。迷ったら `ON` を使ってください。 ON は調べたすべての製品で通ります。

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

10 … うち先頭 4 行を表示

kokyaku_id が 1 本にまとまるので、表名を付けずに書けています。

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

05等号以外も書ける

ON に書けるのは等号だけではありません。真偽が決まる式なら何でも書けます。

範囲で対応させる(金額が階級表のどの区分に入るか)、不等号で組み合わせを作る(自分より前の行だけ)といった使い方があります。

ただし等号以外は照合の手間が大きく、行数が多いと遅くなります。まずは等号で書けないかを考えてください。

同じ分類で「安い方と高い方」の組を作る
SELECT a.shohin_name AS yasui, b.shohin_name AS takai
FROM shohin a
JOIN shohin b ON a.price < b.price AND a.category = b.category
ORDER BY a.category, a.price, b.price;
yasuitakai
書棚デスクチェア
デスクライトキーボード
ボールペンノート
ボールペン付箋
ノート付箋

5

同じ表を 2 回使っています(自己結合)。不等号で組み合わせを作る例です。

自分で打ってみる

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

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

解いてみる

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

関連するトピック

  • INNER JOINON を使う基本の形です。
  • LEFT / RIGHT OUTER JOINON と WHERE の違いが結果に出るのは外部結合のときです。
  • CROSS JOINON を書き忘れると、これと同じ総当たりになります。
  • WHERE 句つないだ後の絞り込み。役割の違いを押さえてください。

根拠(一次情報)