テーブルの結合(JOIN)

MySQL ver 5.6.38を使用しています

テーブルとテーブルの結合のお話。

テーブルAの情報とテーブルBの情報をいっぺんにSELECTしたいとき、ありますよね
そんな時にJOINします

種類としては2コ覚えればいいと思います

ずばり、内部結合と外部結合です

 

内部結合(JOIN)

正確にはINNER JOIN、でもJOINと書いても一緒です

説明するより、実際にやってみるのが早いので、

例として、employeeとwork_locationという2コのテーブルをJOINします。

2つのテーブルに以下のようなデータが入っている前提

001_individual_select

以下のSQLで結合してSELECT

SELECT
  * 
FROM
  `employee` JOIN `work_location` 
    ON `employee`.`id` = `work_location`.`employee_id`;

結果、以下のようにSELECTされます

002_join_select

employeeテーブルのidが4と5の田中さん、伊藤さんが、work_locationテーブルに存在しないので、結果に出てこないのが内部結合の特徴です。

田中さんと伊藤さんは内部結合から仲間外れにされてしまいます・・・

 

【解説】

1~3行目はただのSELECT * FROMなので、飛ばして

■4行目

`employee` JOIN `work_location`

employeeテーブルにwork_locationを結合したいので、JOIN句を挟んで並べます

 

■5行目

ON `employee`.`id` = `work_location`.`employee_id`;

それぞれのテーブルのレコードを紐づけさせるカラムをONの後に指定します

今回はemployeeテーブルのidカラムとwork_locationテーブルのemployee_idカラムの2つで、合致するレコードが紐づいています

書き方は、ONの後に

ON `table_nameA`.`col_nameA` = `table_nameB`.`col_nameB`

です。

複数のカラムを結合条件にしたい場合は、続いて、ANDの後に同じように指定します。

ON `table_nameA`.`col_nameA` = `table_nameB`.`col_nameB`
AND `table_nameA`.`col_nameC` = `table_nameB`.`col_nameD`

みたいな感じ

 

外部結合(LEFT JOIN、RIGHT JOIN)

続いて外部結合、コイツも本来はOUTER JOINですが、OUTERは省略しても一緒です

同じようにemployeeとwork_locationテーブルで試してみましょう

構文はJOINの前にLEFTを追加するだけ

 

SELECT
  * 
FROM
  `employee` LEFT JOIN `work_location` 
    ON `employee`.`id` = `work_location`.`employee_id`

 

今度は以下のようにSELECTされます

003_left_join

 

さっきの内部結合と違って、田中さん伊藤さんも結果に出てきますね

ただ、work_locationに合致するレコードがないので、値はNULLになっています。

work_locationに合致しなくても、employeeにレコードがあれば、NULLで持ってくるのが外部結合の特徴です。

 

また、RIGHT JOINも性質は一緒です

違いはどっちのテーブルをベースにして結合するか否か

試しにLEFTをRIGHTに変えてみます

004_right_join

 

LEFT JOINの時のNULLレコードがなくなっていますね

これはwork_locationをベースにして、employeeをくっつけているから。

work_locationにそもそも存在しないレコードはSELECTされません

 

最後にJOIN時のサブクエリも少しご紹介

サブクエリ

例えば、テーブルAに対してWHERE句を指定してSELECTした結果や、また別のテーブルと結合した結果などを基にして、さらにJOINしたい場合もあります

そんなときはサブクエリ

例として、employeeのidを1と2のみにして、そのあとにJOINするパターンをご紹介

 

SELECT
  * 
FROM
  (SELECT
     * 
   FROM `employee` 
   WHERE `id` < 3) as t1
     JOIN `work_location` 
       ON t1.`id` = `work_location`.`employee_id`

 

4~7行目の()で囲まれた中に、もう1コSQL文がありますよね

ここがサブクエリ、employeeテーブルのidについて、1と2だけSELECTしています

この結果を7行目のasを挟んで、t1という別名をつけました

つまりは、t1(idが1,2だけのemployee)とwork_locationの結合です

 

結果は以下

005_sub_query

ただ、結合やサブクエリはやりすぎると性能が悪くなって激遅になるので要注意!

以前勤めていた現場では、ローカルPCシステム時代に使っていたレガシーSQLを捨てられずに、SaaS化、機能拡張、ユーザ増などを繰り返していたために、5コも10コもJOINしたSQLをVIEWにして、さらにそいつにJOINしてJOINしてJOINして・・・

てなSQLが蔓延していたので、繁忙期になるとDBサーバ君が悲鳴をあげ、必ずシステムが遅延、阿鼻叫喚。

からの悪玉SQL探して~、チューニングして~、お客さんに怒られて~、で徹夜はアタリマエのまさに地獄でした。

性能の話は始めると深すぎますが、全部作り終わった後に地獄を見る前に、ちょっとずつ気にしていった方が吉ですね

まあ、どえらい性能問題に直面しないとなかなか気をつけられないんですが

2 件のコメント

  1. 世紀末リーダー 返信

    徹夜はからだにわるいです。ご自愛ください(`・ω・´)

  2. mobkin 投稿者返信

    >世紀末リーダーさん
    この業界だとなかなか避けられない場面もあったりで、なかなか大変ですよね。。
    日々の工夫などで時短を図ったり、身体を壊さないことも重要だと感じます。

世紀末リーダー へ返信する コメントをキャンセル

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です