Laravel:Eloquentで2つのテーブルの不一致を抽出する
目次
Laravel:Eloquentで2つのテーブルの不一致を抽出する
私はもともとフレームワークを使わずPHPを書いていたので作成した自作システムを作るまでDBの抽出はSQLを直接書いていました。その為、自作システム作成初期に書いたコードは(Eloquentでの文が分からず)DB::と書き出したものがいくつかあります。でもこれ、Laravelの中だと処理が多少遅いようで現在Eloquentに書換をしています。
そんな中「不一致Queryが超楽じゃん!」との感想と「???」との感想と共にあった為、備忘録としてここに記載します。
超簡単な不一致QueryのEloquentコード【doesntHave】
ノーマルなSQLではこんな感じでしょう。
1 2 3 |
select * From tableA Left Join tableB On (tableA.connect_id = tableB.id) Where tableB.id IS NULL |
やっている事は次の通りです。
- tableAにtableBを見える形(Left Join)で結合する
- JoinしたのにtableBが関連づいていない(NULLである)tableAを抽出する
- 結果、tableBに存在しないtableAのレコードが取り出される
これが、なんとEloquentだと一発!
1 2 3 |
# 'tableB'にはテーブル名ではなくtableB のModel名を記載 $query = tableA::doesntHave('tableB')->get(); |
これは超楽。破壊力半端ない。
もうちょっと複雑に取得するなら【whereDoesntHave】
JOIN先のテーブルで抽出条件を付けいたい時があります。その時は【whereDosentHave】が重宝します。
1 2 3 4 5 6 |
#tableB.number = 1、tableB.shop_id = NULL の時の値との不一致を抽出 $query1 = tableA::whereDoesntHave('tableB', function ($a){ $a->where('number',1) ->whereNull('shop_id'); })->get(); |
お~~、これはSQL書くよりだいぶ楽です。
但し、予定と違う値が抽出されてしまうことがあり、少し悩みました。
抽出条件 whereNotNullがもう一つ絡むと何故か正しい値が取得できない。
1 2 3 4 5 |
$query1 = tableA::whereDoesntHave('tableB', function ($a){ $a->where('number',1) ->whereNull('shop_id') ->whereNotNull('item_id'); })->get(); |
何をしたかったかと言うと次の通りです。
- 商品ID(tableB.item_id)が存在する
- 店舗ID(tableB.shop_id)が空白
- tableB.number=1
- 1~3の条件を満たすレコードが無いtableAのリストを作成
上のEloquentでは何故か1~3をともに満たす条件ではなく【商品ID(tableB.item_id)が存在する】商品が抽出されてしまいました。これは次のように分けて書く事で改善しました。
1 2 3 4 5 6 7 8 9 10 11 |
$query = tableA::orderBy('id','asc'); $query->whereDoesntHave('tableB', function ($a){ $a->where('number',1) ->whereNull('shop_id'); }); $query->whereHas('tableB', function ($b){ $b->whereNotNull('item_id'); }); $query1 = $query->get(); |
whereNotNULLが orWhereNotNULLの様に扱われた点は謎です。が解決策を見つけたので良しとしましょう。
何よりもDB::よりも明らかに処理が早い!40万レコードあっても待つのは一瞬です。
まとめ
いやぁ~、Eloquentってすごい!
-
前の記事
Laravel:JOBが同期処理は動くのに非同期処理にすると動かない 2019.09.25
-
次の記事
楽天市場のAPIマニュアルを信じるな!画像更新APIでドはまりした事。 2019.10.30
コメントを残す