关于批量更新

怎么优雅的批量更新数据,不再foreach里操作

rt
路漫漫其修远兮,吾将上下而求索
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 28

file 还有就是 Model->where(条件)->update()

3年前 评论

file 我也是批量更新,好无奈

3年前 评论

有一个依赖包laravelBatch,可以优雅的批量更新

use App\Models\User;

$userInstance = new User;
$value = [
     [
         'id' => 1,
         'status' => 'active',
         'nickname' => 'Mohammad'
     ] ,
     [
         'id' => 5,
         'status' => 'deactive',
         'nickname' => 'Ghanbari'
     ] ,
];
$index = 'id';

Batch::update($userInstance, $value, $index);
3年前 评论
悠悠山雨 3年前
半人间 3年前
pigzzz 3年前
悠悠山雨 3年前
congcong 3年前
congcong 3年前
congcong 3年前

sql 的 case when 语句可以满足你

3年前 评论

自己拼 SQL,,,就是楼上的 case,,,然后可以封装一下?

3年前 评论

@muggle 好的谢谢 没想到这个语法

3年前 评论
czy2020
            $tableName = DB::getTablePrefix() . $this->getTable(); // 表名
            $firstRow = current($multipleData);
            $updateColumn = array_keys($firstRow);
            // 默认以id为条件更新,如果没有ID则以第一个字段为条件
            $referenceColumn = isset($firstRow['id']) ? 'id' : current($updateColumn);
            unset($updateColumn[0]);
            // 拼接sql语句
            $updateSql = "UPDATE " . $tableName . " SET ";
            $sets = [];
            $bindings = [];
            foreach ($updateColumn as $uColumn) {
                $setSql = "`" . $uColumn . "` = CASE ";
                foreach ($multipleData as $data) {
                    $setSql .= "WHEN `" . $referenceColumn . "` = ? THEN ? ";
                    $bindings[] = $data[$referenceColumn];
                    $bindings[] = $data[$uColumn];
                }
                $setSql .= "ELSE `" . $uColumn . "` END ";
                $sets[] = $setSql;
            }
            $updateSql .= implode(', ', $sets);
            $whereIn = collect($multipleData)
                             ->pluck($referenceColumn)
                              ->values()
                              ->all();
            $bindings = array_merge($bindings, $whereIn);
            $whereIn = rtrim(str_repeat('?,', count($whereIn)), ',');
            $updateSql = rtrim($updateSql, ", ") . " WHERE `" . $referenceColumn . "` IN (" . $whereIn . ")";
            // 传入预处理sql语句和对应绑定数据
            return DB::update($updateSql, $bindings);
3年前 评论
bing 3年前

用sql解决吧,case when

3年前 评论

用我的吧,用过很多年了,绝对没问题,还支持自动维护时间字段。

<?php

namespace App;

use Illuminate\Support\Facades\DB;

/**
 * 模型基类
 *
 * @package App\Models
 * @author brad <brader.wen@gmail.com>
 * @date 2020-08-28
 */
class Model extends \Illuminate\Database\Eloquent\Model
{
    /**
     * @var string
     */
    protected $connection = 'mysql';

    /**
     * 创建时间
     */
    const CREATED_AT = 'create_time';

    /**
     * 更新时间
     */
    const UPDATED_AT = 'update_time';

    /**
     * @var string 日期格式
     */
    protected $dateFormat = 'U';

    /**
     * @var array 不可被批量赋值的属性
     */
    protected $guarded = ['id'];

    /**
     * @var string
     */
    protected $table = '';

    /**
     * 存储
     *
     * @param array $args
     * @return Mixed
     */
    public function store(array $args)
    {
        if (empty($args)) {
            return false;
        }

        $model = new static($args);
        $model->save();

        return $model;
    }

    /**
     * 存储
     *
     * @param array $args
     * @return Mixed
     */
    protected function _insert(array $args)
    {
        if (empty($args)) {
            return false;
        }

        return DB::table($this->table)->insert($args);
    }

    /**
     * 批量更新
     *
     * @param array $inputs
     * @param string $where_field
     * @param string $when_field
     * @return mixed
     *
     * [['id' => 1, 'status' => 1], ['id' => 2, 'status' => 1]]
     *
     * update users set name =
     *    case
     *    when id = 1 then 'a'
     *    when id = 2 then 'b'
     * where id in (1,2);
     */
    public function updateBatch(array $inputs, $where_field = 'id', $when_field = 'id')
    {
        if (empty($inputs)) {
            throw new \InvalidArgumentException('The update data is empty.');
        }
        if (!($where = array_pluck($inputs, $where_field)) || !($when = array_pluck($inputs, $when_field))) {
            throw new \InvalidArgumentException('Missing update condition');
        }
        $when_arr = [];
        foreach ($inputs as $k => $input) {
            if (true == $this->timestamps && !is_null(static::UPDATED_AT)) {
                $input[static::UPDATED_AT] = time();
            }

            $when_val = $input[$when_field] ?? '';
            if (1 > strlen($when_val)) throw new \InvalidArgumentException('inputs when field must be require');
            foreach ($input as $key => $value) {
                if ($key == $when_field) continue;
                $when_arr[$key][] = "when {$when_field} = '{$when_val}' then '{$value}'";
            }
        }
        $build = DB::connection($this->getConnectionName())->table($this->getTable())->whereIn($where_field, $where);
        foreach ($when_arr as $key => &$item) {
            $item = DB::raw('case ' . implode(' ', $item) . ' end ');
        }
        return $build->update($when_arr);
    }

    /**
     * 批量创建
     *
     * @param array $inputs
     * @return bool
     */
    public function storeBatch(array $inputs)
    {
        if (true == $this->timestamps) {
            foreach ($inputs as $key => $input) {
                $time = time();
                if (!is_null(static::CREATED_AT)) {
                    $inputs[$key][static::CREATED_AT] = $time;
                }
                if (!is_null(static::UPDATED_AT)) {
                    $inputs[$key][static::UPDATED_AT] = $time;
                }
            }
        }
        $query = DB::connection($this->getConnectionName())->table($this->getTable());
        return $query->insert($inputs);
    }
}
3年前 评论
surest 3年前
congcong 3年前

case when 导致SQL巨长,感觉异步使用比较好

3年前 评论
congcong 3年前
虚妄 (作者) 3年前

用能驾驭的方式就是最好的

3年前 评论
虚妄 3年前

我认为如果数据结构可以用分表更新的话最好,大概就是多出一个表来把这个表里的数据更新到另一张表,没有sql长度限制而且很快。

3年前 评论

一个条件,一个条件的更新挺好的,非要整合成一条复杂性就明显提高了,foreach 更新,更好读且易维护

3年前 评论

我也遇到了这个问题 订单表 关联了 3到4张 需要同时更新保证数据不出错 我一开始是foreach后记录 一个个记录id 然后再foreach循环插入另外几张表。但是这样就费时间

3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!