Laravel 实现批量更新

LaravelORM 没有类似 ThinkPHPsaveAll 函数可以实现批量更新的操作。

比如需要对一列数据进行排序并保存时,在不支持批量更新的情况下,就需要进行 foreach 更新,对于数据库的操作次数过多。

需要自行封装函数,实现 CASE ... THEN ... 逻辑:

UPDATE orders SET `order` = CASE id
    WHEN 1 THEN 1
    WHEN 3 THEN 2
    WHEN 5 THEN 3
    WHEN 4 THEN 4
END,
`remark` = CASE id
    WHEN 1 THEN 'remark1'
    WHEN 3 THEN 'remark3'
    WHEN 5 THEN 'remark5'
    WHEN 4 THEN 'remark4'
END
WHERE id IN(1,3,5,4);

可能在其它的 Model 中也会遇到同样的需求,先封装成一个 Trait,在需要使用的 Model 中通过 use 使用:

trait BatchTrait
{
    public function updateBatch(array $params = [])
    {
        if (empty($params)) {
            return false;
        }
    
        // 获取表名,并拼接上表前缀
        $table_name = config('database.connections.mysql.prefix') . $this->getTable();
        
        $first_row = reset($params);
    
        $fields = array_keys($first_row);
        // 如果有 id 以 id 为主,如果没有,以数组的第一个字段为条件
        $condition = isset($first_row['id']) ? 'id' : reset($fields);
    
        $sql = 'UPDATE ' . $table_name . ' SET ';
        $bindings = [];
        foreach ($fields as $key => $field) {
            if ($condition == $field) {
                // 跳过
                continue;
            }
        
            $sql .= '`' . $field . '` = CASE ' . $condition . ' ';
            foreach ($params as $param) {
                $sql .= 'WHEN ? THEN ? ';
                // $sql .= 'WHEN ' . $param[$condition] . ' THEN ' . $param[$field] . ' ';
                $bindings[] = $param[$condition];
                $bindings[] = $param[$field];
            }
            $sql .= 'END ';
        
            if ($key + 1 != count($fields)) {
                $sql .= ', ';
            }
        }
    
        $sql .= 'WHERE ' . $condition . ' IN ' . '(' . implode(',', array_column($params, 'id')) . ')';
        
        DB::update($sql, $bindings);
    }
}
Posted in PHP

发表评论

您的电子邮箱地址不会被公开。