Laravelのページネーションでdistinct
を使うと総ヒット件数が正しく計算されない。
自分はLaravel 5.2で経験したが、最新のバージョンだと修正されているかもしれない(が調べたところ5.4ではおかしいらしい)(いや、修正されたのか??)。
https://stackoverflow.com/questions/41283083/distinct-with-pagination-in-laravel-5-2-not-working
https://github.com/laravel/framework/issues/21242
distinct
を使わなければいいのだが、そうはいかない場合もある。
そこで対応したのが以下の方法(5.2を想定)。
例だとdistinct
を使う意味がないと思うがそこは複雑なSQLを脳内補完してほしい。
DB::enableQueryLog();
$page = 2;
$limit = 20;
$builder = User::select('id', 'name')->distinct()->orderBy('id', 'desc');
$users = $builder->skip(($page - 1) * $limit)->take($limit)->get();
// totalの計算
$queries = DB::getQueryLog();
$last_query = end($queries);
$total_query = preg_replace('/\sorder\sby.+?$/', '', $last_query['query']);
$total = DB::select(DB::raw('select count(*) as total from (' . $total_query . ') tmp_users'), $last_query['bindings']);
DB::disableQueryLog();
クエリーログを有効化して、最後に実行したSQLを取得する。
$last_query['query']
にそのSQLが格納されているのだが、そこには
select distinct `id`, `name` from `users` order by `id` desc limit 20 offset 20
が入っていて、これだと総件数は求められない。
そこで正規表現でorder by
以下を削除する。
select distinct `id`, `name` from `users`
これをselect count(*)
することでdistinctでも正しい総件数が得られるようになる。
以上