Laravel批量更新

Laravel批量更新,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);

我试图更新一个表,其中包含一个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);
大约有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')