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()
在检查剩余记录量是否小于块大小的行上?