概要
where()とorWhere()組み合わせることで、WHERE句のANDやORを表現できる。ここではこれらのメソッドの書き方と生成されるSQL、条件の組み合わせの優先順位を整理する。
以下のようなメソッドの書き方が可能になる。
- 条件1 OR 条件2 AND 条件3で- ANDが優先される書き方
- (条件1 OR 条件2) AND 条件3で括弧内の- ORが優先される書き方
where()やorWhere()については、クエリービルダーのメソッドを参照。
準備
クエリービルダーで使った以下の3つのテーブルで各メソッドを確認する。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | mysql> SELECT * FROM customers; +----+-----------+ | id | name      | +----+-----------+ |  1 | customer1 | |  2 | customer2 | |  3 | customer3 | +----+-----------+ 3 rows in set (0.00 sec) mysql> SELECT * FROM emails; +----+-------------+--------------------+ | id | customer_id | email              | +----+-------------+--------------------+ |  1 |           1 | customer1@mail.com | |  2 |           2 | customer2@mail.com | +----+-------------+--------------------+ 2 rows in set (0.00 sec) mysql> SELECT * FROM orders; +----+-------------+---------------------+---------------+ | id | customer_id | ordered_at          | item          | +----+-------------+---------------------+---------------+ |  1 |           1 | 2020-06-05 00:00:00 | screw         | |  2 |           2 | 2020-06-05 00:00:00 | rubber sheet  | |  3 |           2 | 2020-06-06 00:00:00 | plastic plate | |  4 |           1 | 2020-06-07 00:00:00 | rubber sheet  | |  5 |           3 | 2020-06-08 00:00:00 | wire          | +----+-------------+---------------------+---------------+ 5 rows in set (0.00 sec) | 
これをordersに対してcustomersとemailsを左結合で関連付けて並べると以下のとおり。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | mysql> SELECT     ->   o.id, o.ordered_at, o.item, c.id, c.name, e.address     -> FROM orders AS o     -> LEFT JOIN customers AS c ON o.customer_id = c.id     -> LEFT JOIN emails AS e ON c.id = e.customer_id; +----+---------------------+---------------+------+-----------+--------------------+ | id | ordered_at          | item          | id   | name      | address            | +----+---------------------+---------------+------+-----------+--------------------+ |  1 | 2020-06-05 00:00:00 | screw         |    1 | customer1 | customer1@mail.com | |  2 | 2020-06-05 00:00:00 | rubber sheet  |    2 | customer2 | customer2@mail.com | |  3 | 2020-06-06 00:00:00 | plastic plate |    2 | customer2 | customer2@mail.com | |  4 | 2020-06-07 00:00:00 | rubber sheet  |    1 | customer1 | customer1@mail.com | |  5 | 2020-06-08 00:00:00 | wire          |    3 | customer3 | NULL               | +----+---------------------+---------------+------+-----------+--------------------+ 5 rows in set (0.00 sec) | 
チェーンの展開とANDの優先
where()やorWhere()をチェーンで連ねた場合、それぞれの条件が単純にANDあるいはORで連ねられる。その結果ANDが処理された後ORが処理される。
- ...->where(条件)は- '... AND 条件'
- ...->orWhere(条件)は- '... OR 条件'
以下の例では、where()->orWhere()->where()とメソッドチェーンを組んでいる。
| 1 2 3 |         $orders = Order::where('item', '=', 'wire')             ->orWhere('item', '=', 'rubber sheet')             ->where('customer_id', '=', 1)->get(); | 
上記のクエリービルダーで生成されるSQLは以下のとおり。
| 1 2 3 4 | >>> Order::where('item', '=', 'wire')-> ... orWhere('item', '=', 'rubber sheet')-> ... where('customer_id', '=', 1)->toSql() => "select * from `orders` where `item` = ? or `item` = ? and `customer_id` = ?" | 
この結果AND演算が優先され、「item='wire'または、item='rubber sheet'かつid=1」という条件で2つのデータが抽出される。
- 4: 2020-06-07 00:00:00
- customer name: customer1
- email address: customer1@mail.com
- ordered item : rubber sheet
 
- 5: 2020-06-08 00:00:00
- customer name: customer3
- email address:
- ordered item : wire
 
クロージャによる()の表現
ANDに対してORの条件を優先させたい場合、SQLでは括弧で括る。クエリービルダーでは、括弧で括りたい処理をクロージャ―でまとめる。
where(function($query) { 括弧でまとめたい処理群; })
以下の例では、上の例と順番は同じだが、最初のwhere()とorWhere()をクロージャ―でまとめている。
| 1 2 3 4 |         $orders = Order::where(function($q) {             $q->where('item', '=', 'wire')             ->orWhere('item', '=', 'rubber sheet');         })->Where('customer_id', '=', 1)->get(); | 
この結果、まず最初の2項のOR演算が処理され、その結果と残りの条件のAND演算で抽出処理される。生成されるSQLは以下のとおりでOR演算が括弧で括られている。
| 1 2 3 4 5 | >>> Order::where(function($q) { ...   $q->where('item', '=', 'wire') ...     ->orWhere('item', '=', 'rubber sheet'); ... })->Where('customer_id', '=', 1)->toSql(); => "select * from `orders` where (`item` = ? or `item` = ?) and `customer_id` = | 
実行結果は以下のとおりで、「item='wire'またはitem='rubber sheet'」で3つのデータが抽出され、その結果とid=1のANDで結果が一つに絞り込まれる。
- 4: 2020-06-07 00:00:00
- customer name: customer1
- email address: customer1@mail.com
- ordered item : rubber sheet