Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/laravel/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/video/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 如何在Laravel中分块自定义查询的结果_Php_Laravel_Eloquent_Laravel 4 - Fatal编程技术网

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

Php 如何在Laravel中分块自定义查询的结果,php,laravel,eloquent,laravel-4,Php,Laravel,Eloquent,Laravel 4,我有一个自定义查询,它从旧系统中获取数据并将其映射到新系统中的模型。查询如下所示: <?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 = (

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

<?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. */
}
select * from (...) somealias LIMIT ... OFFSET ...
$companys=DB::connection('legacy')->选择(“…”

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

我如何实现这一点


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

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();
    }
});

我相信您可以在查询生成器上使用
chunk
。例如

DB::connection('legacy')->select("...")->chunk(200, function($companies){
    //do something with $companies
});

试着这样做:

<?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. */
}
select * from (...) somealias LIMIT ... OFFSET ...

deyes的答案有一个bug

原样

如果“legacy”表有“id”列,并且有1,2,3,4,5。。。100号数据

<?php

$max = 10;
$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. */

    $legacyIds = $legacy->lists("id");
    echo "i = " . $i . ": \n";
    print_r($legacyIds);
}

//Result
i = 1: 
Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => 4
    [4] => 5
    [5] => 6
    [6] => 7
    [7] => 8
    [8] => 9
    [9] => 10
)
i = 2: 
Array
(
    [0] => 12
    [1] => 13
    [2] => 14
    [3] => 15
    [4] => 16
    [5] => 17
    [6] => 18
    [7] => 19
    [8] => 20
    [9] => 21
) ...

这些答案对我都不管用。我基于@deyes answer创建了自己的函数

private static function chunk($query, $max, $function) {
    $counter = preg_replace('/SELECT (.*?) FROM/', 'SELECT COUNT(*) FROM', $query);
    $total = DB::connection('legacy')->select($counter)[0];
    $total = (array)$total;
    $total = $total['COUNT(*)'];

    $pages = ceil($total / $max);

    for ($i = 1; $i < ($pages + 1); $i++) {
        $offset = (($i - 1)  * $max);
        $start = ($offset == 0 ? 0 : ($offset + 1));
        $items = DB::connection('legacy')->select($query . ' LIMIT ' . $offset . ', ' . $max);

        $function($items);

        unset($items);
    }
}

请注意,这是一个简单的快速修复,您的查询可能必须相当简单,因为我正在使用search replace来构建计数查询,我只是在查询的末尾加上限制X,Y,但它对我有效。

功能仅适用于有说服力的模型和QueryBuilder请求,例如

DB::table('tbl')->where('num', '>', 3)->chunk(500, function($rows) {
    // process $rows
});
但是它不适用于
DB::select(“…”)
request。 您需要使用QueryBuilder请求,或使用基础PDO对象来查询数据库,例如:

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

更新:2018年3月在查询生成器类中添加了一个新函数。现在可以使用Sub中的
实现同样的功能:

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

DB::query()->fromSub($subQuery, 'alias')->orderBy('alias.id')->chunk(200, function ($chunk) {
    // Do something
});
要使用不同的连接,请从
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
});
laravel执行的查询如下所示:

<?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. */
}
select * from (...) somealias LIMIT ... OFFSET ...

这至少应该在Laravel 5.1中起作用。但是我看不出为什么它不能在4+中工作。

这一页上的许多答案都会查找所有记录,以确定有多少“页面”。这可能很慢,而且不需要,因为我们不是分页,而是分块。我们只需要知道总页数,当我们分页显示给用户

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

    $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++;
    }
$recordsRemaining=true;
$lookupsCompleted=0;
$chunkSize=200;
while($recordsRemaining){
$companys=DB::connection('legacy')->select(“…”->skip($chunkSize*$lookupcompleted)->take($chunkSize)->get();
如果($legacy->count()<$chunkSize){
$recordsRemaining=false;
}
foreach($公司作为$公司){
//做点什么
}
$lookupsCompleted++;
}

这与公认的答案完全相同,但效率更高

尝试使用orderBy子句:

DB::table('tbl')->where('num', '>', 3)->orderBy('id')->chunk(500, function($rows) {
    // process $rows
});

我尝试过这种方法,但不幸的是,我现在没有得到任何输出。我也尝试过这种方法。函数($companys)内部不会返回任何内容。为什么不尝试这样做:
var\u dump($companys);退出在chuck函数中查看是否返回任何内容。
公司
表中有多少行?嗯,还是没有。有数千条记录,但我现在将结果限制在10条。此外,当我使用非分块方法时,我确实会得到结果。嗯,不是$total=DB::connection('legacy')->select(“…”->count();在清点物品的同时取下所有物品?有点违背了这个目的:(额外的开销是你做了很多数据库请求,而不是仅仅one@MaciejSwic为了让您和未来的人们看到这一点,我将count()行更改为
DB::select('select count(*)as rows')[0]->rows
以返回它。
$legacy->count()
从何而来?您的意思是
$companys->count()
在检查剩余记录量是否小于块大小的行上?