概要
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