Laravel 分页不适用于 group by 子句

Posted

技术标签:

【中文标题】Laravel 分页不适用于 group by 子句【英文标题】:Laravel pagination not working with group by clause 【发布时间】:2014-05-29 05:49:18 【问题描述】:

似乎 Laravel 分页无法与 group by 子句一起正常工作。例如:

$users = Subject::select(DB::raw('subjects.*, count(user_subjects.id) as total_users'))
            ->join('user_subjects', 'user_subjects.subject_id', '=', 'subjects.id')
            ->whereNull('user_subjects.deleted_at')
            ->groupBy('subjects.id')
            ->orderBy('subjects.updated_at', 'desc')
            ->paginate(25);

制作

select subjects.*, count(user_subjects.id) as total_users 
from `subjects` inner join `user_subjects` on `user_subjects`.`subject_id` = `subjects`.`id` 
where `subjects`.`deleted_at` is null and `user_subjects`.`deleted_at` is null 
group by `subjects`.`id` 
order by `subjects`.`updated_at` desc

请注意,查询中没有 limit 子句。

如果查询中没有 group by 子句,则工作正常:

$users = Subject::select(DB::raw('subjects.*, count(user_subjects.id) as total_users'))
            ->join('user_subjects', 'user_subjects.subject_id', '=', 'subjects.id')
            ->whereNull('user_subjects.deleted_at')
            ->orderBy('subjects.updated_at', 'desc')
            ->paginate(25);

产生了以下查询:

select subjects.*, count(user_subjects.id) as total_users from `subjects` 
inner join `user_subjects` on `user_subjects`.`subject_id` = `subjects`.`id`
where `subjects`.`deleted_at` is null and `user_subjects`.`deleted_at` is null 
order by `subjects`.`updated_at` desc 
limit 25 offset 0

有人知道我该如何解决这个问题吗?

【问题讨论】:

不知道为什么,但是使用 groupBy 的分页器无法在 Laravel 中处理这个问题。它基本上是检索整个集合,并在 php 端对结果进行切片。在这种情况下,您最好手动执行或以不同方式获取所需的计数。 以上是正确的——如果你查看代码,你会发现分页器会尽可能添加LIMITs,但只要查询有GROUP BY它进入一种模式,它必须获取所有结果并使用array_slice 在 PHP 中手动进行分页。我曾经环顾分页器类,实际上认为分页器没有使用LIMITs 是一个错误,但后来意识到只有当它是GROUP BY 语句时才发现。所以是的 - 你会发现分页器应该工作正常,只是效率低下。我只是希望你没有一个巨大的结果集! @alexrussell 谢谢。问题是我们有很大的数据集:(。 那么不幸的是,你自己的分页似乎是唯一的方法。 【参考方案1】:

如果你想分组和分页,这很有效。

$code = DB::table('sources')
    ->select(DB::raw('sources.id_code,sources.title,avg(point) point'))
    ->join('rating','sources.id_code','rating.id_code')
    ->groupBy('sources.id_code')
    ->groupBy('sources.title')
    ->groupBy('sources.language')
    ->groupBy('sources.visited')
    ->paginate(5);

【讨论】:

【参考方案2】:

我知道这是一个老问题,我正在分享我的解决方案以供将来参考。

我设法编写了一个基于this link 的函数,它完成了确定复杂查询的分页的繁重工作。只需传递“QueryBuilder”,它将返回分页对象/集合。

此外,此过程还可以跟踪和维护除page= 之外的其他参数。

public function mergeQueryPaginate(\Illuminate\Database\Eloquent\Builder $query): \Illuminate\Pagination\LengthAwarePaginator
    
        $raw_query = $query;
        $totalCount = $raw_query->get()->count();

        $perPage = request('per-page', 10);
        $page = request('page', 1);
        $skip = $perPage * ($page - 1);
        $raw_query = $raw_query->take($perPage)->skip($skip);

        $parameters = request()->getQueryString();
        $parameters = preg_replace('/&page(=[^&]*)?|^page(=[^&]*)?&?/', '', $parameters);
        $path = url(request()->getPathInfo() . '?' . $parameters);

        $rows = $raw_query->get();

        $paginator = new LengthAwarePaginator($rows, $totalCount, $perPage, $page);
        $paginator = $paginator->withPath($path);
        return $paginator;
    

【讨论】:

【参考方案3】:

    创建一个数据库view,命名为vw_anythingmysql 查询会像

    create view vw_anything as select subjects.*, count(user_subjects.id) as total_users from subjects inner join user_subjects on user_subjects.subject_id = subjects.id wheresubjects.deleted_at is null and user_subjects.deleted_at is null group bysubjects.id;

    现在为此视图创建一个名为 UserSubModel 的新模型,protected $table = 'vw_anything';

    现在您的分页查询将类似于UserSubModel::orderBy('subjects.updated_at', 'desc')->paginate(25);

.

回答这个问题Laravel Pagination group by year and month only

查看查询将是:

create view vw_anything as select gallery.*, DATE_FORMAT(created_at, "%Y-%m") as tanggal,count(created_at) as jumlah from gallery group by tanggal;

让你的模型是 VwModel 那么你的分页查询将是

VwModel::where('type','Foto')->orderBy('tanggal','desc')->paginate(2);

【讨论】:

【参考方案4】:

这在 laravel 5.2 中适用于我

Select(\DB::RAW("assignment_descendant_child.assignment_descendant_child_id, assignment_descendant_child.assignment_descendant_child_name, COUNT(assignment_descendant.assignment_descendant_id) as xNum"))
            ->leftJoin(
                'assignment_descendant',
                'assignment_descendant.assignment_descendant_child_id',
                '=',
                'assignment_descendant_child.assignment_descendant_child_id'
            )
            ->orderBy('assignment_descendant_child_name')
            ->groupBy('assignment_descendant_child.assignment_descendant_child_id')
            ->paginate(\Config::get('constants.paginate_org_index'))

【讨论】:

【参考方案5】:

查看文档 https://laravel.com/docs/5.2/pagination

目前,使用groupBy 语句的分页操作不能 由 Laravel 高效执行。如果您需要使用groupBy 分页结果集,建议查询数据库 并手动创建分页器。

【讨论】:

以上是关于Laravel 分页不适用于 group by 子句的主要内容,如果未能解决你的问题,请参考以下文章

Group by 语句不适用于 Select Case

分页不适用于 POST 动作 laravel 5

Laravel 分页不适用于数组而不是集合

当我在`dplyr`之后加载`plyr`时,为啥汇总或变异不适用于group_by?

当我在`dplyr`之后加载`plyr`时,为啥汇总或变异不适用于group_by?

GROUP BY不适用于MySQL 5.7,因为5.7使用SQL_MODE的“ONLY_FULL_GROUP_BY”选项。