mysql更新语句很简单,更新一条数据的某个字段,一般这样写:
UPDATE mytable SET myfield = ‘value’ WHERe other_field = ‘other_value’;
如果更新同一字段为同一个值,mysql也很简单,修改下
where
即可:
UPDATE mytable SET myfield = ‘value’ WHERe other_field in (‘other_values’);
这里注意,
other_values
是一个逗号
,
分隔的字符串,如:
1,2,3
那如果是MySQL批量修改不同的记录为不同的值呢?
1 常规方案
那如果修改多条数据为不同的值,可能很多人会这样写:
foreach ($display_order as $id => $ordinal) {
$sql = "UPDATE categories SET display_order = $ordinal WHERe id =
i
d
"
;
m
y
s
q
l
q
u
e
r
y
(
id"; mysql_query(
id";mysqlquery(sql);
}
即是循环一条一条的更新记录。
一条记录
update
一次,这样性能很差,也很容易造成阻塞。
2 高效方案
那么能不能一条sql语句实现批量更新呢?
2.1 CASE WHEN
mysql并没有提供直接的方法来实现批量更新,但是可以用点小技巧来实现。
UPDATE mytable SET
myfield = CASE id
WHEN 1 THEN ‘value’
WHEN 2 THEN ‘value’
WHEN 3 THEN ‘value’
END
WHERe id IN (1,2,3)
这里使用了
case when
这个小技巧来实现批量更新。
举个例子:
UPDATE categories SET
display_order = CASE id
WHEN 1 THEN 3
WHEN 2 THEN 4
WHEN 3 THEN 5
END
WHERe id IN (1,2,3)
这句sql的意思是,更新
display_order
字段:
如果
id=1
则
display_order
的值为
3
,
如果
id=2
则
display_order
的值为
4
,
如果
id=3
则
display_order
的值为
5
。
即是将条件语句写在了一起。
这里的
where
部分不影响代码的执行,但是会提高sql执行的效率。
确保sql语句仅执行需要修改的行数,这里只有
3
条数据进行更新,而
where
子句确保只有
3
行数据执行。
3.2 更新多值
如果更新多个值的话,只需要稍加修改:
UPDATE categories SET
display_order = CASE id
WHEN 1 THEN 3
WHEN 2 THEN 4
WHEN 3 THEN 5
END,
title = CASE id
WHEN 1 THEN ‘New Title 1’
WHEN 2 THEN ‘New Title 2’
WHEN 3 THEN ‘New Title 3’
END
WHERe id IN (1,2,3)
到这里,已经完成一条mysql语句更新多条记录了。
但是要在业务中运用,需要结合服务端语言。
3.3 封装成PHP函数
在PHP中,我们把这个功能封装成函数,以后直接调用。
为提高可用性,我们考虑处理更全面的情况。
如下时需要更新的数据,我们要根据
id
和
parent_id
字段更新
post
表的内容。
其中,
id
的值会变,
parent_id
的值一样。
$data = [
[‘id’ => 1, ‘parent_id’ => 100, ‘title’ => ‘A’, ‘sort’ => 1],
[‘id’ => 2, ‘parent_id’ => 100, ‘title’ => ‘A’, ‘sort’ => 3],
[‘id’ => 3, ‘parent_id’ => 100, ‘title’ => ‘A’, ‘sort’ => 5],
[‘id’ => 4, ‘parent_id’ => 100, ‘title’ => ‘B’, ‘sort’ => 7],
[‘id’ => 5, ‘parent_id’ => 101, ‘title’ => ‘A’, ‘sort’ => 9],
];
例如,我们想让
parent_id
为
100
、
title
为
A
的记录依据不同
id
批量更新:
echo batchUpdate($data, ‘id’, [‘parent_id’ => 100, ‘title’ => ‘A’]);
其中,
batchUpdate()
实现的PHP代码如下:
function batchUpdate($data, $field, KaTeX parse error: Expected '}', got 'EOF' at end of input: … if (!is_array(data) || !
f
i
e
l
d
∣
∣
!
i
s
a
r
r
a
y
(
field || !is_array(
field∣∣!isarray(params)) {
return false;
}
u
p
d
a
t
e
s
=
p
a
r
s
e
U
p
d
a
t
e
(
updates = parseUpdate(
updates=parseUpdate(data, $field);
w
h
e
r
e
=
p
a
r
s
e
P
a
r
a
m
s
(
where = parseParams(
where=parseParams(params);
// 获取所有键名为
f
i
e
l
d
列
的
值
,
值
两
边
加
上
单
引
号
,
保
存
在
field列的值,值两边加上单引号,保存在
field列的值,值两边加上单引号,保存在fields数组中
// array_column()函数需要PHP5.5.0+,如果小于这个版本,可以自己实现,
f
i
e
l
d
s
=
a
r
r
a
y
c
o
l
u
m
n
(
fields = array_column(
fields=arraycolumn(data, $field);
f
i
e
l
d
s
=
i
m
p
l
o
d
e
(
′
,
′
,
a
r
r
a
y
m
a
p
(
f
u
n
c
t
i
o
n
(
fields = implode(',', array_map(function(
fields=implode(′,′,arraymap(function(value) {
return “’”.$value."’";
}, $fields));
$sql = sprintf(“UPDATE %s SET %s WHERe %s IN (%s) %s”, ‘post’, $updates, $field, $fields, $where);
return $sql;
}
function parseUpdate($data, $field)
{
$sql = ‘’;
k
e
y
s
=
a
r
r
a
y
k
e
y
s
(
c
u
r
r
e
n
t
(
keys = array_keys(current(
keys=arraykeys(current(data));
foreach ($keys as $column) {
$sql .= sprintf("`%s` = CASE `%s` n", $column, $field);
foreach ($data as $line) {
$sql .= sprintf("WHEN '%s' THEN '%s' n", $line[$field], $line[$column]);
}
$sql .= "END,";
}
return rtrim($sql, ‘,’);
}
function parseParams($params)
{
w
h
e
r
e
=
[
]
;
f
o
r
e
a
c
h
(
where = []; foreach (
where=[];foreach(params as $key => $value) {
$where[] = sprintf("%s = ‘%s’", $key, $value);
}
return $where ? ’ AND ’ . implode(’ AND ', $where) : ‘’;
}
得到这样一个批量更新的SQL语句:
UPDATE post SET id = CASE id
WHEN ‘1’ THEN ‘1’
WHEN ‘2’ THEN ‘2’
WHEN ‘3’ THEN ‘3’
WHEN ‘4’ THEN ‘4’
WHEN ‘5’ THEN ‘5’
END,parent_id = CASE id
WHEN ‘1’ THEN ‘100’
WHEN ‘2’ THEN ‘100’
WHEN ‘3’ THEN ‘100’
WHEN ‘4’ THEN ‘100’
WHEN ‘5’ THEN ‘101’
END,title = CASE id
WHEN ‘1’ THEN ‘A’
WHEN ‘2’ THEN ‘A’
WHEN ‘3’ THEN ‘A’
WHEN ‘4’ THEN ‘B’
WHEN ‘5’ THEN ‘A’
END,sort = CASE id
WHEN ‘1’ THEN ‘1’
WHEN ‘2’ THEN ‘3’
WHEN ‘3’ THEN ‘5’
WHEN ‘4’ THEN ‘7’
WHEN ‘5’ THEN ‘9’
END WHERe id IN (‘1’,‘2’,‘3’,‘4’,‘5’) AND parent_id = ‘100’ AND title = ‘A’
生成的SQL把所有的情况都列了出来。
不过因为有
WHERe
限定了条件,所以只有
id
为
1
、
2
、
3
这几条记录被更新。
如果只需要更新某一列,其他条件不限,那么传入的
$data
可以更简单:
d
a
t
a
=
[
[
′
i
d
′
=
>
1
,
′
s
o
r
t
′
=
>
1
]
,
[
′
i
d
′
=
>
2
,
′
s
o
r
t
′
=
>
3
]
,
[
′
i
d
′
=
>
3
,
′
s
o
r
t
′
=
>
5
]
,
]
;
e
c
h
o
b
a
t
c
h
U
p
d
a
t
e
(
data = [ ['id' => 1, 'sort' => 1], ['id' => 2, 'sort' => 3], ['id' => 3, 'sort' => 5], ]; echo batchUpdate(
data=[[′id′=>1,′sort′=>1],[′id′=>2,′sort′=>3],[′id′=>3,′sort′=>5],];echobatchUpdate(data, ‘id’);
这样的数据格式传入,就可以修改
id
从
1~3
的记录,将
sort
分别改为
1、3、5
。
得到SQL语句:
UPDATE post SET id = CASE id
WHEN ‘1’ THEN ‘1’
WHEN ‘2’ THEN ‘2’
WHEN ‘3’ THEN ‘3’
END,sort = CASE id
WHEN ‘1’ THEN ‘1’
WHEN ‘2’ THEN ‘3’
WHEN ‘3’ THEN ‘5’
END WHERe id IN (‘1’,‘2’,‘3’)
这种情况更加简单高效。



