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)
该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 的分页器所做的事情,而没有额外的开销。
更新: 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+ 中工作。
此页面上的许多答案都会查找所有记录,以便计算出有多少“页面”。这可能会很慢,并且不需要,因为我们不是分页,而是分块。我们在分页时只需要知道总页数即可向用户展示。
因此,在开始时获取所有记录计数的另一种方法是执行以下操作:
$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)
这与已接受的答案完全相同,但效率更高。