Laravel批量更新
我试图更新一个表,其中包含一个slug值,每个记录都有随机slugLaravel批量更新,laravel,laravel-4,eloquent,laravel-5,Laravel,Laravel 4,Eloquent,Laravel 5,我试图更新一个表,其中包含一个slug值,每个记录都有随机slug $vouchers = Voucher->get(); // assume 10K for example foreach ($vouchers as $voucher) { $q .= "UPDATE vouchers set slug = '" . Str::random(32) . "' WHERE id = " . $voucher->id . ";"; } DB::statement($q);
$vouchers = Voucher->get(); // assume 10K for example
foreach ($vouchers as $voucher) {
$q .= "UPDATE vouchers set slug = '" . Str::random(32) . "' WHERE id = " . $voucher->id . ";";
}
DB::statement($q);
大约有200万条记录,所以我需要批量执行。把它作为单独的记录来做太费时了。我似乎找不到一种方法来批量运行它们,比如说一组10公里或其他什么
尝试了一系列
->update()
和DB::statement
的变体,但似乎无法将其执行。分块结果是在不消耗所有RAM的情况下执行此类操作的最佳方法,Laravel支持开箱即用的分块结果
例如:
Voucher::chunk(2000, function($vouchers)
{
foreach ($vouchers as $voucher)
{
//
}
});
凭证::区块(2000,功能($凭证)
{
foreach($凭证作为$凭证)
{
//
}
});
我已经在
CodeIgniter
中为多个更新创建了自定义函数,如Update\u batch
只需将此函数放置在任何模型中,或者您可以创建帮助器类并将此函数放置在该类中:
//test data
/*
$multipleData = array(
array(
'title' => 'My title' ,
'name' => 'My Name 2' ,
'date' => 'My date 2'
),
array(
'title' => 'Another title' ,
'name' => 'Another Name 2' ,
'date' => 'Another date 2'
)
)
*/
/*
* ----------------------------------
* update batch
* ----------------------------------
*
* multiple update in one query
*
* tablename( required | string )
* multipleData ( required | array of array )
*/
static function updateBatch($tableName = "", $multipleData = array()){
if( $tableName && !empty($multipleData) ) {
// column or fields to update
$updateColumn = array_keys($multipleData[0]);
$referenceColumn = $updateColumn[0]; //e.g id
unset($updateColumn[0]);
$whereIn = "";
$q = "UPDATE ".$tableName." SET ";
foreach ( $updateColumn as $uColumn ) {
$q .= $uColumn." = CASE ";
foreach( $multipleData as $data ) {
$q .= "WHEN ".$referenceColumn." = ".$data[$referenceColumn]." THEN '".$data[$uColumn]."' ";
}
$q .= "ELSE ".$uColumn." END, ";
}
foreach( $multipleData as $data ) {
$whereIn .= "'".$data[$referenceColumn]."', ";
}
$q = rtrim($q, ", ")." WHERE ".$referenceColumn." IN (". rtrim($whereIn, ', ').")";
// Update
return DB::update(DB::raw($q));
} else {
return false;
}
}
它将产生:
UPDATE `mytable` SET `name` = CASE
WHEN `title` = 'My title' THEN 'My Name 2'
WHEN `title` = 'Another title' THEN 'Another Name 2'
ELSE `name` END,
`date` = CASE
WHEN `title` = 'My title' THEN 'My date 2'
WHEN `title` = 'Another title' THEN 'Another date 2'
ELSE `date` END
WHERE `title` IN ('My title','Another title')
如果有人像我一样进入此页面,laravel允许批量更新,如下所示:
$affectedRows=document::where('id','=',$document->id)->更新(数组('slug'=>Str::random(32))代码>
请参阅下的“更新检索到的模型”,我在Laravel项目中使用了批量更新功能。它可能对任何想在Laravel中使用批更新查询的人都有用。其第一个参数是表名字符串,第二个参数是要根据其更新行的键名字符串,大多数情况下,它将是“id”,第三个参数是以下格式的数据数组:
array(
array(
'id' => 1,
'col_1_name' => 'col_1_val',
'col_2_name' => 'col_2_val',
//...
),
array(
'id' => 2,
'col_1_name' => 'col_1_val',
'col_2_name' => 'col_2_val',
//...
),
//...
);
函数将返回受影响的行数。功能定义:
private function custom_batch_update(string $table_name = '', string $key = '', Array $update_arr = array()) {
if(!$table_name || !$key || !$update_arr){
return false;
}
$update_keys = array_keys($update_arr[0]);
$update_keys_count = count($update_keys);
for ($i = 0; $i < $update_keys_count; $i++) {
$key_name = $update_keys[$i];
if($key === $key_name){
continue;
}
$when_{$key_name} = $key_name . ' = CASE';
}
$length = count($update_arr);
$index = 0;
$query_str = 'UPDATE ' . $table_name . ' SET ';
$when_str = '';
$where_str = ' WHERE ' . $key . ' IN(';
while ($index < $length) {
$when_str = " WHEN $key = '{$update_arr[$index][$key]}' THEN";
$where_str .= "'{$update_arr[$index][$key]}',";
for ($i = 0; $i < $update_keys_count; $i++) {
$key_name = $update_keys[$i];
if($key === $key_name){
continue;
}
$when_{$key_name} .= $when_str . " '{$update_arr[$index][$key_name]}'";
}
$index++;
}
for ($i = 0; $i < $update_keys_count; $i++) {
$key_name = $update_keys[$i];
if($key === $key_name){
continue;
}
$when_{$key_name} .= ' ELSE ' . $key_name . ' END, ';
$query_str .= $when_{$key_name};
}
$query_str = rtrim($query_str, ', ');
$where_str = rtrim($where_str, ',') . ')';
$query_str .= $where_str;
$affected = DB::update($query_str);
return $affected;
}
我必须将这一行更改为,这样它才能工作,在$data[$referenceColumn]$q.=“WHEN”$referenceColumn.=“$data[$referenceColumn]。“'THEN'”。$data[$uColumn]。“”;在那之后,它按照所描述的那样工作:-)注意:我还在最后一个$q赋值之前添加了以下行,以从wereIn列表中删除最后一个额外的逗号$其中=rtrim($其中,',');我已经修剪了','。请仔细检查。看起来你做错了什么我认为没有任何值被转义,并且查询容易受到SQL注入的攻击这仍然需要用户进行200万次DB调用,而不是批量更新。我认为你实际上在寻找的是凭证::其中('id',[…])->更新([…])
。这称为“批量更新”因为它不会将模型加载到内存中,例如执行模型事件。哈哈,谢谢@Charles Wood!不幸的是,其中()->update()只允许您对多个模型执行单个更新,而不是并行执行多个更新。您只提供了通过读取数据库进行分块的解决方案。批量更新在哪里?这易受MySQL注入攻击!
UPDATE table_name SET col_1_name = CASE
WHEN id = '1' THEN 'col_1_value'
WHEN id = '2' THEN 'col_1_value'
ELSE col_1_name END,
col_2_name = CASE
WHEN id = '1' THEN 'col_2_value'
WHEN id = '2' THEN 'col_2_value'
ELSE col_2_name END
WHERE id IN('1','2')