【问题标题】:How to use pagination with laravel DB::select query如何在 laravel DB::select 查询中使用分页
【发布时间】:2017-10-20 18:50:07
【问题描述】:

我正在 Laravel 中开展一个项目,并使用 DB 外观来运行 sql 的原始查询。 就我而言,我使用的是 DB::select,问题是分页方法不适用于此 DB 原始查询并显示此错误

Call to a member function paginate() on array

我只想如何使用 DB 原始查询实现 laravel 分页 这是我的代码:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Notice;
use Illuminate\Support\Facades\DB;
use Illuminate\Pagination\Paginator;
use Illuminate\Pagination\LengthAwarePaginator;

class NoticeController extends Controller
{

public function index(){

    $notices = DB::select('select 
notices.id,notices.title,notices.body,notices.created_at,notices.updated_at,
    users.name,departments.department_name
    FROM notices
    INNER JOIN users ON notices.user_id = users.id
    INNER JOIN departments on users.dpt_id = departments.id
    ORDER BY users.id DESC')->paginate(20);

    $result = new Paginator($notices,2,1,[]);

    return view('welcome')->with('allNotices', $notices);
 }
}

【问题讨论】:

  • 你已经在使用-&gt;paginate(20),你为什么还要使用new Paginator?对于阅读本文的任何人,请始终尝试了解您在写什么,从字面上阅读您写的内容,它具有“语义”,分页器分页没有逻辑……并尽量避免原始查询,始终使用模型,并且只有在你有一个非常复杂的查询并且 Eloquent 无法解决它或者比普通的SQL 更难阅读时才使用DB

标签: php mysql laravel pagination


【解决方案1】:
public function index(Request $request){

$notices = DB::select('select notices.id,notices.title,notices.body,notices.created_at,notices.updated_at,
users.name,departments.department_name
FROM notices
INNER JOIN users ON notices.user_id = users.id
INNER JOIN departments on users.dpt_id = departments.id
ORDER BY users.id DESC');

$notices = $this->arrayPaginator($notices, $request);

return view('welcome')->with('allNotices', $notices);

}

public function arrayPaginator($array, $request)
{
    $page = Input::get('page', 1);
    $perPage = 10;
    $offset = ($page * $perPage) - $perPage;

    return new LengthAwarePaginator(array_slice($array, $offset, $perPage, true), count($array), $perPage, $page,
        ['path' => $request->url(), 'query' => $request->query()]);
}

【讨论】:

  • 它拯救了我的一天。内置 paginate() 函数的出色定制。非常感谢兄弟。
  • 非常感谢,这里已经保存了一天,我的查询有一些计算,无法正常工作
  • 这个分页不是在php级别而不是在mysql级别吗?您正在从 mysql 获取所有行,然后在 php 级别进行切片?如果我错了,请纠正我。 @Tymur Abdullaiev
  • 谢谢! array_slice 函数需要将保留键设置为 false。原因是,第一页上的数据结构因为 true 标志在保留数组键中为后续页面更改。将其设置为 false 可以为所有页​​面维护分页器类的一致数据结构。
  • 这是可行的,但效率不高,如果您选择 100 万行怎么办?你应该在 Mysql 而不是 PHP 中这样做
【解决方案2】:

试试:

$notices = DB::table('notices')
        ->join('users', 'notices.user_id', '=', 'users.id')
        ->join('departments', 'users.dpt_id', '=', 'departments.id')
        ->select('notices.id', 'notices.title', 'notices.body', 'notices.created_at', 'notices.updated_at', 'users.name', 'departments.department_name')
        ->paginate(20);

【讨论】:

  • 您的代码还提供了有关如何在 laravel 中实现连接的帮助...再次感谢
  • 如何对上述结果进行水合,以便可以访问关系以获取通知。
【解决方案3】:

永远不要在 php 端使用分页逻辑! 在您的 sql 上使用 limit 和 offset 并将其余部分留给数据库服务器。 额外为您的语句使用单独的计数选择。

计数:

$sql_count = 'SELECT count(1) cnt FROM ('. $sql . ') x';
$result = \DB::select( DB::raw($sql_count) );
$data['count'] = $result[0]->cnt;

结果:

$sql .= ' LIMIT ' . $offset . ', ' . $limit; 

$result = \DB::select( DB::raw($sql) );
$myPaginator = new \Illuminate\Pagination\LengthAwarePaginator($result, $data['count'], $limit, $page, ['path' => action('MyController@index')]);
$data['result'] = $result;

【讨论】:

    【解决方案4】:

    这个适合我

    $sql = "some sql code";
    
    $page = 1;
    $size = 10;
    $data = DB::select($sql);
    $collect = collect($data);
    
    $paginationData = new LengthAwarePaginator(
                             $collect->forPage($page, $size),
                             $collect->count(), 
                             $size, 
                             $page
                           );
    

    【讨论】:

      【解决方案5】:

      它对我有用,请参阅 首先在你的控制器中使用

      use Illuminate\Pagination\Paginator;
      

      然后在函数中

      $query =  DB::select(DB::raw("SELECT pro.* , (SELECT TIMESTAMPDIFF(DAY,updated_at,'$current_date') from users as u where u.id=pro.id) as days FROM users as pro where role_id = 6 and delete_status=0 and user_status = 'A' and approved_status = 1 and is_clever_courier = 1 having days >= 5"));
      
           
      $page1 = new Paginator($query, $maxPage);
      
      dd($page1);
      

      o/p =>

      Paginator {#1450 ▼
        #hasMore: true
        #items: Collection {#1509 ▼
          #items: array:10 [▼
            0 => {#1454 ▶}
            1 => {#1455 ▶}
            2 => {#1456 ▶}
            3 => {#1457 ▶}
            4 => {#1458 ▶}
            5 => {#1459 ▶}
            6 => {#1460 ▶}
            7 => {#1461 ▶}
            8 => {#1462 ▶}
            9 => {#1463 ▶}
          ]
        }
        #perPage: 10
        #currentPage: 1
        #path: "/"
        #query: []
        #fragment: null
        #pageName: "page"
        +onEachSide: 3
        #options: []
      

      【讨论】:

        【解决方案6】:

        在尝试了这么多事情之后,我找到了解决方案,并且对我来说效果很好,也许对其他人会有所帮助。

        首先,在 PHP 类中使用 Illuminate\Pagination\LengthAwarePaginator:

        use Illuminate\Pagination\LengthAwarePaginator;
        
        public function index(Request $request) {
            $notices = DB::select('SELECT notices.id, notices.title, notices.body, notices.created_at, notices.updated_at, users.name,departments.department_name
            FROM notices
            INNER JOIN users ON notices.user_id = users.id
            INNER JOIN departments on users.dpt_id = departments.id
            ORDER BY users.id DESC');
            
            $notices = $this->arrayPaginator($notices, $request);
            
            return view('welcome')->with('allNotices', $notices);
        }
            
        public function arrayPaginator($array, $request) {
                $page = Input::get('page', 1);
                $perPage = 10;
                $offset = ($page * $perPage) - $perPage;
        
                return new LengthAwarePaginator(
                    array_slice(
                        $array,
                        $offset,
                        $perPage,
                        true
                    ),
                    count($array),
                    $perPage,
                    $page,
                    ['path' => $request->url(), 'query' => $request->query()]
                );
        }
        

        【讨论】:

        • 这个答案根本没有性能,避免这个 100%。此查询不限于每个“页面”,而是获取数据库上的所有数据,然后 PHP 对其进行切片,完全疯狂。您可能有 100k 条记录,DB 将获取所有记录,而 PHP 将耗尽内存...此外,您正在复制 Laravel 已经在查询后使用简单的 ->paginate(10) 所做的事情...不需要重新发明轮子……
        • 是的,paginate(10) 已经足够好了,但是我建议在您使用 DB:raw 查询获取数据时使用自定义分页,那么您将无法使用“->页面(10)”函数。因此,在这种情况下,您必须使用自定义分页或其他解决方案,即您可以将原始查询转换为雄辩的查询。
        • 尽量避免使用raw sql,如果需要使用,不要用它写和整个sql,使用方法select、table、join等...
        猜你喜欢
        • 2019-10-25
        • 2020-01-08
        • 2018-01-31
        • 2017-07-03
        • 1970-01-01
        • 1970-01-01
        • 2018-09-05
        • 1970-01-01
        • 2019-02-22
        相关资源
        最近更新 更多