Laravel中为自定义SELECT查询添加分页器问题求助
我来帮你解决这个Laravel分页集成的问题!你现在用的是原生SELECT查询,DB::select()返回的是结果数组,没法直接调用Laravel内置的paginate()方法,这里给你两种可行的解决方案:
方法一:将原生查询转换为查询构造器(推荐)
这种方式更符合Laravel的开发习惯,而且能直接利用框架的分页功能,代码也更易维护。你可以把原生SQL里的字段选择、关联逻辑用查询构造器的方法重写,比如:
$results = DB::table('shop_product') // 根据你的实际关联关系调整join条件,这里假设shop_product和shops通过shop_id关联 ->join('shops', 'shop_product.shop_id', '=', 'shops.id') // 用selectRaw写入距离计算的SQL片段 ->selectRaw('(6371 * acos( cos( radians(23.0376279) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(72.5102283) ) + sin( radians(23.0376279) ) * sin( radians( latitude ) ) )) AS distance') // 选择你需要的其他字段 ->select( 'shop_product.stock', 'shop_product.price', 'shops.id AS shopId', // 补充你原查询里的其他字段 ) // 可选:按距离排序 ->orderBy('distance', 'asc') // 设置每页显示条数,这里是10,你可以按需修改 ->paginate(10);
这样$results就是一个标准的Laravel分页器实例,你可以直接在视图里用{!! $results->links() !!}渲染分页链接,也能使用分页器的所有方法(比如currentPage()、lastPage()等)。
方法二:手动创建分页器(适合坚持用原生查询的场景)
如果你不想修改原生查询,可以手动构建LengthAwarePaginator来实现分页,步骤如下:
// 获取当前页码,默认是1 $page = request()->get('page', 1); // 设置每页显示的记录数 $perPage = 10; // 计算偏移量 $offset = ($page - 1) * $perPage; // 执行带分页参数的原生查询,注意在SQL末尾加上LIMIT和OFFSET $results = DB::select( 'SELECT distances.* FROM (SELECT ( 6371 * acos( cos( radians(23.0376279 ) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(72.5102283 ) ) + sin( radians(23.0376279 ) ) * sin( radians( latitude ) ) ) ) AS distance, shopdatabase.shop_product.stock, shopdatabase.shop_product.price AS price, shopdatabase.shops.id AS shopId, shopdatabase... ) AS distances LIMIT ? OFFSET ?', [$perPage, $offset] ); // 获取总记录数,需要写对应的计数查询(把原查询的SELECT部分替换为COUNT(*)) $total = DB::selectOne( 'SELECT COUNT(*) AS total FROM (SELECT ( 6371 * acos( cos( radians(23.0376279 ) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(72.5102283 ) ) + sin( radians(23.0376279 ) ) * sin( radians( latitude ) ) ) ) AS distance, shopdatabase.shop_product.stock, shopdatabase.shop_product.price AS price, shopdatabase.shops.id AS shopId, shopdatabase... ) AS distances' )->total; // 创建LengthAwarePaginator实例 $paginator = new \Illuminate\Pagination\LengthAwarePaginator( $results, $total, $perPage, $page, [ 'path' => \Illuminate\Pagination\Paginator::resolveCurrentPath(), 'pageName' => 'page', ] ); // 之后你可以把$paginator传给视图,用法和普通分页器一致 return view('your-view', ['results' => $paginator]);
注意事项
- 方法一优先推荐,因为查询构造器会自动处理表前缀(如果你在config里设置了的话),而且能更好地预防SQL注入。
- 如果你的距离计算需要作为筛选条件(比如只显示距离X公里内的店铺),可以在查询构造器里加
->having('distance', '<=', $maxDistance)(需要配合groupBy,或者在Laravel 8+里可以直接用havingWithoutGroupBy)。
内容的提问来源于stack exchange,提问作者Subrata Mallik
相关产品推荐
相关产品推荐

