如何从Laravel中的自定义查询中分块结果

Don*_*nie 8 php eloquent laravel-4

我有一个自定义查询,它从旧系统中获取数据并将其映射到新系统中的模型.查询如下所示:

$companies = DB::connection('legacy')->select("...");

由于它是大量数据,我想使用Eloquent的块功能(只是从他们的文档中复制的示例代码):

User::chunk(200, function($users)
{
    foreach ($users as $user)
    {
        //
    }
});
Run Code Online (Sandbox Code Playgroud)

我该如何实现?


编辑:我的代码现在看起来像这样,导致没有响应:

DB::connection('legacy')->select("SELECT * FROM companies")->chunk(200, function($companies) {
    foreach ($companies as $company) {
        // dd($company);
        $entity       = Entity::firstOrNew(['external_id' => $company->companyKey]);
        $entity->name = $company->companyName;
        $entity->save();
    }
});
Run Code Online (Sandbox Code Playgroud)

Ale*_*exM 8

chunk功能仅适用于Eloquent模型和QueryBuilder请求,例如

DB::table('tbl')->where('num', '>', 3)->chunk(500, function($rows) {
    // process $rows
});
Run Code Online (Sandbox Code Playgroud)

但它不适用于DB::select('...')请求.您需要使用QueryBuilder请求,或使用基础PDO对象来查询数据库,例如:

$pdo = DB::getPdo();
$sth = $pdo->prepare("SELECT ....");
$sth->execute();
while ($row = $sth->fetch(PDO::FETCH_ASSOC))
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)


小智 7

尝试这样的事情:

<?php

$max = 100;
$total = DB::connection('legacy')->select("...")->count();
$pages = ceil($total / $max);
for ($i = 1; $i < ($pages + 1); $i++) {
    $offset = (($i - 1)  * $max);
    $start = ($offset == 0 ? 0 : ($offset + 1));
    $legacy = DB::connection('legacy')->select("...")->skip($start)->take($max)->get();
    /* Do stuff. */
}
Run Code Online (Sandbox Code Playgroud)

基本上复制了 Laravel 的分页器所做的事情,而没有额外的开销。

  • 嗯,不是 $total = DB::connection('legacy')-&gt;select("...")-&gt;count(); 在计数的同时获取所有对象?有点违背目的:( (2认同)

Art*_*äpp 6

更新: 2018 年 3 月,查询构建器类中添加了一个新函数。现在可以使用fromSub以下方法实现相同的目标:

$subQuery = DB::table('users')->where(...);

DB::query()->fromSub($subQuery, 'alias')->orderBy('alias.id')->chunk(200, function ($chunk) {
    // Do something
});
Run Code Online (Sandbox Code Playgroud)

并使用不同的连接开始 DB::connection('legacy')->query()


旧答案:偶然发现这个问题,但在某些情况下可能会派上用场的小技巧。

$query = 'SELECT * FROM ... JOIN ... UNION ... WHATEVER ... GROUP BY';

// This is the important part:
$query = '(' . $query . ') somealias';

DB::connection('legacy')->table(DB::raw($query))->chunk(1000, function($rows){
    // Do something
});
Run Code Online (Sandbox Code Playgroud)

查询 laravel 执行然后是这样的:

select * from (...) somealias LIMIT ... OFFSET ...
Run Code Online (Sandbox Code Playgroud)

这应该至少在 Laravel 5.1 中有效。但我不明白为什么它不应该在 4+ 中工作。


Sam*_*ner 5

此页面上的许多答案都会查找所有记录,以便计算出有多少“页面”。这可能会很慢,并且不需要,因为我们不是分页,而是分块。我们在分页时只需要知道总页数即可向用户展示。

因此,在开始时获取所有记录计数的另一种方法是执行以下操作:

    $recordsRemaining = true;
    $lookupsCompleted = 0;
    $chunkSize = 200;

    while($recordsRemaining){
       $companies = DB::connection('legacy')->select("...")->skip($chunkSize*$lookupsCompleted)->take($chunkSize)->get();

       if($legacy->count() < $chunkSize){
          $recordsRemaining = false;
       }
       foreach($companies as $company){
          //Do something
       }

       $lookupsCompleted++;
    }
Run Code Online (Sandbox Code Playgroud)

这与已接受的答案完全相同,但效率更高。