批量更新 - Laravel

时间:2017-03-27 11:05:05

标签: laravel laravel-5

我试图找到一次更新多条记录,就像我们insert一次创建多条记录一样。

假设我有一个关联的数组,其中包含要在表员工的每一行中更新的数据:

$data = [
  ['id'=>1,'name'=>'xxx'],
  ['id'=>2,'name'=>'xxx'],
  ['id'=>3,'name'=>'xxx'],
  ['id'=>4,'name'=>'xxx']
];

更新所有这些记录的一种方法是:

foreach($data as $d){
   Employee::where('id'=>$d['id'])->update(['name'=>$d['name']]);
}

其中Employee是员工表的模型。

我想知道我是否可以通过一行声明更新所有记录?

例如,如果我从$ data创建了新记录,我会使用:

Employee::insert($data);

而不是循环遍历$ data并为每条记录使用create()。

还有类似的更新吗?

9 个答案:

答案 0 :(得分:0)

不,这是不可能的,你应该迭代数组并分别更新每一行。

答案 1 :(得分:0)

你试过Employee::update($data);吗?当然数据应该是数组 喜欢: $data = (['name'=>'test'],['surname'=>'test2'])); - 它将更新表中的所有行 - 但您可以添加where条件。

答案 2 :(得分:0)

Doctrine允许您进行批量插入/更新。您可以在此处找到它:http://www.laraveldoctrine.org/

答案 3 :(得分:0)

使用集合做这样的事情呢。

$data = [
  ['id'=>3,'name'=>'xxx'],
  ['id'=>4,'name'=>'xxx'],
  ['id'=>5,'name'=>'xxx']
];

Employee::find(collect($data)->pluck('id')->toArray())->map(function($item, $key) use ($data){
  $item['name'] = $data[$key]['name'];
  return $item->save();
});

答案 4 :(得分:0)

这是不可能的,因为批量更新只能通过union来实现,/// <summary> /// A stackpanel similar to the Wpf stackpanel. /// </summary> public class StackPanel: FlowLayoutPanel { public StackPanel(): base() { InitializeComponent(); this.ForceAutoresizeOfControls = true; } private void InitializeComponent() { this.SuspendLayout(); // // StackPanel // this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; this.WrapContents = false; this.ResumeLayout(false); } /// <summary> /// Override it just in order to hide it in design mode. /// </summary> [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public new bool WrapContents { get { return base.WrapContents; } set { base.WrapContents = value; } } /// <summary> /// Override it just in order to set its default value. /// </summary> [DefaultValue(typeof(AutoSizeMode), "GrowAndShrink")] public override AutoSizeMode AutoSizeMode { get { return base.AutoSizeMode; } set { base.AutoSizeMode = value; } } /// <summary> /// Get or set a value that when is true forces the resizing of each control. /// If this value is false then only control that have AutoSize == true will be resized to /// fit the client size of this container. /// </summary> [DefaultValue(true)] public bool ForceAutoresizeOfControls { get; set; } protected override void OnSizeChanged(EventArgs e) { base.OnSizeChanged(e); this.SuspendLayout(); switch (FlowDirection) { case FlowDirection.BottomUp: case FlowDirection.TopDown: foreach (Control control in this.Controls) if (ForceAutoresizeOfControls || control.AutoSize) control.Width = this.ClientSize.Width - control.Margin.Left - control.Margin.Right; break; case FlowDirection.LeftToRight: case FlowDirection.RightToLeft: foreach (Control control in this.Controls) if (ForceAutoresizeOfControls || control.AutoSize) control.Height = this.ClientSize.Height - control.Margin.Top - control.Margin.Bottom; break; default: break; } this.ResumeLayout(); } protected override void OnLayout(LayoutEventArgs levent) { base.OnLayout(levent); if (levent != null && levent.AffectedControl != null) { Control control = levent.AffectedControl; if (ForceAutoresizeOfControls || control.AutoSize) { switch (FlowDirection) { case FlowDirection.BottomUp: case FlowDirection.TopDown: control.Width = this.ClientSize.Width - control.Margin.Left - control.Margin.Right; break; case FlowDirection.LeftToRight: case FlowDirection.RightToLeft: control.Height = this.ClientSize.Height - control.Margin.Top - control.Margin.Bottom; break; default: break; } } } } } 是你可以在sql中使用的最慢的运算符。 否则,即使在原始sql中也无法使用不同行中的不同值批量更新,因此也无法在laravel中进行更新。

答案 5 :(得分:0)

我写了一个批处理更新函数,用于我的Laravel项目。对于想要在laravel中使用批量更新查询的任何人来说,这可能很有用。它的第一个参数 是表名字符串,第二个是要更新一行或多行的键名称字符串,大部分是&#39; id&#39;,第三个参数是数据数组,格式如下: / p>

array(
    array(
        'id' => 1,
        'col_1_name' => 'col_1_value',
        'col_2_name' => 'col_2_value',
        //....
    ),
    array(
        'id' => 2,
        'col_1_name' => 'col_1_value',
        'col_2_name' => 'col_2_value',
        //....
    ),
    //....
);

功能定义:

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')

答案 6 :(得分:0)

它将在laravel中更新现有或新插入到表中。

$data=array(  
    array('id'=>1,'name'=>'kaleemullah@example.com'),
    array('id'=>2,'name'=>'kaleemullah@example.com2'),
    array('id'=>4,'name'=>'kaleemullah@example.com4')
);
$imported =  implode(', ', array_map(function ($string) {
return "(".$string['id'].','."'".$string['name']."'"."),";
}, $data));
$OneStepAway =  str_replace(',,', ',', $imported);
$kale = rtrim($OneStepAway,',');
$s = DB::statement("INSERT INTO  tests (id,name) VALUES $kale
ON DUPLICATE KEY UPDATE name=VALUES(name)") ;
echo "Successfully Updated and Insert New records into the database ";

答案 7 :(得分:0)

对于一小部分数据,循环会很好。

但是,如果您有大量数据-绝对不要循环,因为“数据库事务”是一项昂贵的操作,并且带有for循环,您将结束每次迭代都要进行交易。

在这里,您可以了解如何在不使用for循环的情况下进行更新:

$data = [
  ['id'=>1,'name'=>'xxx'],
  ['id'=>2,'name'=>'xxx'],
  ['id'=>3,'name'=>'xxx'],
  ['id'=>4,'name'=>'xxx']
];

$cases = [];
$ids = [];
$params = [];

foreach ($data as $datum) {
   $id = $datum['id'];

   $cases[] = "WHEN {$id} then ?";
   $params[] = $datum['name'];
   $ids[] = $id;
}

$ids = implode(',', $ids);
$cases = implode(' ', $cases);

if (!empty($ids)) {
    \DB::update("UPDATE employees SET `name` = CASE `id` {$cases} END WHERE `id` in ({$ids})", $params);
}

如果您想阅读有关内容,请选中https://medium.com/@sentiasa/bulk-update-multiple-records-with-separate-data-laravel-3da9131c279a

答案 8 :(得分:0)

public function transaction($callback) {
    DB::connection(**<TABLE_NAME>**)->transaction($callback);
}

public function updateBatch($batchData)
{
    $count = 0;
    try {
        $batchData = array_values($batchData);
        $total = count($batchData);
        $j = 0;
        $i = 0;
        do {
            $j = min($total -1, $j + self::$configBatch);
            DB::connection(**<TABLE_NAME>**)->transaction(function() use ($batchData, &$count, $total, $j, &$i) {
                for (; $i <= $j; $i++) {
                    $batchData[$i]->save();
                    $count++;
                }
            });
        } while ($i < $total);
    } catch (\Exception $exception) {
        print_r($exception->getMessage());
        $count = 0;
    }
    return $count;
}

希望能为您提供帮助