Larave Eloquentからデータベース操作するとき
- サブクエリでテーブル結合したい
- 例えば INNER JOINとかしたり、
- あるいは LEFT JOINとかしたい
こういう場面に遭遇しました。
MySQLでのJOIN文・サブクエリなどを生で書くって方法もあるんですが、それはセキュリティ的に危険すぎますよね。
そこでLaravel Eloquentでサブクエリを使ってテーブル同士を結合(JOIN)する方法をまとめます。忘れがちなので自分用メモ
MySQLでのサブクエリ+JOIN文のテーブル結合の例
まずはLaravelを使わない場合の話から
こういう構成のテーブルがあるとします。
▼ 1つめ : usersテーブル
id | name |
---|---|
1 | チャーリー |
2 | サリー |
3 | ルーシー |
4 | ライナス |
5 | ビッグペン |
▼ 2つめ : user_hobbiesテーブル
id | user_id | hobby |
---|---|---|
1 | 1 | 野球観戦 |
2 | 2 | プラモデル作り |
3 | 2 | 神社仏閣めぐり |
4 | 5 | ソシャゲ課金 |
5 | 3 | ボルダリング |
6 | 1 | バドミントン |
7 | 4 | バイク |
8 | 5 | ハンドメイド |
9 | 3 | バイク |
10 | 4 | 野球観戦 |
1つめのusersテーブルのidカラムがユーザーID、そして2つめのusers_hobbiesテーブルのuser_idカラムがユーザーIDと対応してます。
この2つをusersテーブルに対してusers_hobbiesテーブルを結合させたい場合、次のようなJOIN文を使うことで結合可能です。
▼ このようなSQL例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
SELECT sub1.id, sub1.name, sub2.hobby FROM ( SELECT * FROM users ) AS sub1 INNER JOIN ( SELECT hobby FROM user_hobbies ) AS sub2 ON sub1.id = sub2.post_id |
このSQLにおいては sub1.id = sub2.post_id において結合の共通カラムを指定してます。結合する際はON句に結合条件が必須。(ちなみにFROM句の後のサブクエリは複雑なクエリを想定)
それから分かりやすいようにサブクエリに別名sub1、sub2を付けてます。こういうサブクエリとJOIN文の組み合わせでテーブル結合が可能です。
これをLaravelでやるのに苦戦した・・・
Laravelでサブクエリ+JOIN文でテーブル結合
このやり方が分からなくて困りました。
でも公式リファレンスでも説明されてます。
▼ 上級のJOIN文について
さらに上級なJOIN節を指定することもできます。そのためにはjoinメソッドの第2引数に「クロージャ」を指定します。その「クロージャ」はJOIN節に制約を指定できるようにするJoinClauseオブジェクトを受け取ります。
12345 DB::table('users')->join('contacts', function ($join) {$join->on('users.id', '=', 'contacts.user_id')->orOn(...);})->get();
これを使えば複雑なテーブル結合も楽々です。
実際に先ほどの例でコードを書いてみました。
▼ usersテーブルとusers_hobbiesテーブル結合
1 2 3 4 5 6 7 8 9 |
$hobbies = DB::table('users AS sub1')->selectRaw(' sub1.id, sub1.name, sub2.hobby, ')->join( 'user_hobbies as sub2', function ($join) { $join->on('sub2.user_id', '=', 'sub1.id'); } )->get(); |
このようにjoinメソッドの第1引数に 'user_hobbies as sub2' みたいな結合先テーブル、第2引数に function ($join) {...} のように結合用のクロージャを渡して共通カラムで結合させるだけです。
ちなみにControllerとかModelは省略してます。そこはLaravelの基礎中の基礎なので、分からないならググってください。
このコードのように joinメソッドの第2引数に結合させるためのコールバック巻数を渡すのがキモです。他は何も難しくありません。
ちなみにjoinメソッドではWHEER句の指定も可能
もちろんWHERE句なども追加で指定可能です。
▼ こういったWHERE句の指定もできる
1 2 3 4 5 6 7 8 9 10 |
$post = DB::table('users AS sub1')->selectRaw(' sub1.id, sub1.name, sub2.hobby, ')->join( 'user_hobbies as sub2', function ($join) { $join->on('sub2.user_id', '=', 'sub1.id') ->where('sub2.hobby', 'バイク'); } ) |
これはサブクエリ内でWHERE句指定と同じですね。
こういった複雑なサブクエリも簡潔に書けるのがLaravelの利点の1つなのかも。joinメソッドを使えば多重のテーブル結合も簡単です。
以上、Laravel Eloquentでのサブクエリの結合でした。
もし間違いがあればご指摘ください。ではまた