Laravel 实现批量更新
Laravel
的 ORM
没有类似 ThinkPHP
的 saveAll
函数可以实现批量更新的操作。
比如需要对一列数据进行排序并保存时,在不支持批量更新的情况下,就需要进行 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);
}
}