9

我正在尝试使用每个记录的随机 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 万条记录,所以我需要批量执行。将其作为单独的记录进行处理花费的时间太长了。我似乎找不到批量运行它们的方法,比如以 10K 为一组。

尝试了一堆变化,->update()DB::statement似乎无法让它去。

4

4 回答 4

5

如果有人像我一样登陆这个页面,laravel 允许批量更新:

$affectedRows = Voucher::where('id', '=', $voucher->id)->update(array('slug' => Str::random(32)));

请参阅http://laravel.com/docs/4.2/eloquent#insert-update-delete下的“更新检索到的模型”

于 2014-12-18T14:18:15.197 回答
3

我已经为多个更新创建了我的自定义函数,如update_batch.CodeIgniter

只需将此函数放置在您的任何模型中,或者您可以创建辅助类并将此函数放置在该类中:

//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')
于 2014-12-18T05:43:04.123 回答
-1

分块结果是在不消耗所有 RAM 的情况下执行此类操作的最佳方法,并且 Laravel 支持开箱即用的分块结果。

例如:

  凭证::chunk(2000, function($vouchers)
  {
    foreach ($vouchers 作为 $voucher)
    {
        //
    }
 });
于 2014-10-01T05:30:03.560 回答
-2

我制作了一个批量更新功能以在我的 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;
}

它将像这样生成并执行查询字符串:

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')
于 2018-02-02T13:04:54.323 回答