我知道你可以一次插入多行,有没有办法在MySQL中一次更新多行(如在一个查询中)?
编辑:例如我有以下内容
Name id Col1 Col2
Row1 1 6 1
Row2 2 2 3
Row3 3 9 5
Row4 4 16 8
我想将以下所有更新组合到一个查询中
UPDATE table SET Col1 = 1 WHERE id = 1;
UPDATE table SET Col1 = 2 WHERE id = 2;
UPDATE table SET Col2 = 3 WHERE id = 3;
UPDATE table SET Col1 = 10 WHERE id = 4;
UPDATE table SET Col2 = 12 WHERE id = 4;
17 回答
您可能也有兴趣在更新时使用连接,这也是可能的 .
编辑:如果要更新的值不是来自数据库中的其他位置,则需要发出多个更新查询 .
是的,这是可能的 - 您可以使用INSERT ... ON DUPLICATE KEY UPDATE .
使用你的例子:
由于您具有动态值,因此需要使用IF或CASE来更新列 . 它有点难看,但应该有用 .
使用您的示例,您可以这样做:
问题是陈旧的,但我想用另一个答案来扩展这个话题 .
我的观点是,实现它的最简单方法就是用事务包装多个查询 . 接受的答案
INSERT ... ON DUPLICATE KEY UPDATE
是一个很好的黑客,但应该意识到它的缺点和局限性:如上所述,如果您碰巧使用主键不是't exist in the table, the query inserts new 879494 records. Probably it'的行启动查询
如果你有一个没有默认值的非空字段的表,并且即使你根本没有插入一行,也不会得到
"Field 'fieldname' doesn't have a default value"
MySQL警告 . 如果您决定严格并在应用程序中将mysql警告转换为运行时异常,它会让您遇到麻烦 .我对三个建议的变体进行了一些性能测试,包括
INSERT ... ON DUPLICATE KEY UPDATE
变体,带有"case / when / then"子句的变体和带事务的简单方法 . 你可能会得到python代码和结果here . 总的结论是带有case语句的变体的速度是其他两个变体的两倍,但是很难为它编写正确且注入安全的代码,所以我个人坚持使用最简单的方法:使用事务 .Edit: Dakusan的调查结果证明我的绩效估算不是很有效 . 请参阅this answer进行另一项更精细的研究 .
不确定为什么还没有提到另一个有用的选项:
以下所有内容均适用于InnoDB .
我知道3种不同方法的速度很重要 .
有3种方法:
INSERT:使用ON DUPLICATE KEY UPDATE INSERT
TRANSACTION:您在事务中为每条记录执行更新的位置
CASE:在UPDATE中为每个不同记录的情况/时间
我刚刚测试了这个,并且INSERT方法对我来说比TRANSACTION方法快了 6.7x . 我尝试了一组3,000和30,000行 .
TRANSACTION方法仍然必须运行每个单独的查询,这需要花费时间,尽管它在执行时将结果批处理内存或其他内容 . TRANSACTION方法在复制和查询日志中也相当昂贵 .
更糟糕的是,CASE方法比使用30,000条记录的INSERT方法慢了 41.1x (比TRANSACTION慢6.1倍) . 并且在MyISAM中慢了 75x . INSERT和CASE方法甚至达到了约1,000条记录 . 即使在100条记录中,CASE方法也更快 .
所以一般来说,我觉得INSERT方法最好也最容易使用 . 查询更小,更易于阅读,只需要执行1次操作查询 . 这适用于InnoDB和MyISAM .
Bonus stuff:
INSERT非默认字段问题的解决方案是暂时关闭相关的SQL模式:
SET SESSION sql_mode=REPLACE(REPLACE(@@SESSION.sql_mode,"STRICT_TRANS_TABLES",""),"STRICT_ALL_TABLES","")
. 如果您打算将其恢复,请务必先保存sql_mode
.至于我看过的其他评论说auto_increment使用INSERT方法上升了,我也测试了它,但似乎并非如此 .
运行测试的代码如下 . 它还输出.SQL文件以删除php解释器开销
这应该适用于你 .
the MySQL manual中有一个对多个表的引用 .
使用临时表
您可以使用同一个表的别名来为您提供要插入的ID(如果您正在进行逐行更新:
此外,显而易见的是,您也可以从其他表更新 . 在这种情况下,更新会兼作“SELECT”语句,为您提供您指定的表中的数据 . 您在查询中明确说明了更新值,因此第二个表不受影响 .
有一个你可以改变的设置称为“多语句”,它禁用MySQL的“安全机制”,以防止(多个)注入命令 . 对于MySQL的“精彩”实现而言,它也是典型的,它也会阻止用户进行有效的查询 .
这里(http://dev.mysql.com/doc/refman/5.1/en/mysql-set-server-option.html)是关于设置的C实现的一些信息 .
如果你正在使用PHP,你可以使用mysqli来做多个语句(我认为php已经附带了mysqli一段时间了)
希望有所帮助 .
为什么没有人提到 multiple statements in one query ?
在php中,你使用mysqli实例的
multi_query
方法 .来自php manual
以下是与更新30,000 raw中的其他3种方法进行比较的结果 . 代码可以找到here,这是基于@Dakusan的回答
Transaction: 5.5194580554962 Insert: 0.20669293403625 Case: 16.474853992462 Multi: 0.0412278175354
如您所见,多语句查询比最高答案更有效 .
如果您收到如下错误消息:
您可能需要增加mysql配置文件中的
max_allowed_packet
,该文件在我的机器中是/etc/mysql/my.cnf
然后重新启动mysqld .使用
请注意:
id必须是主要唯一键
如果使用外键引用表,则REPLACE删除然后插入,因此这可能会导致错误
以下将更新一个表中的所有行
下一个将更新Column2的值大于5的所有行
有Unkwntech更新多个表的例子
是..可以使用INSERT ON DUPLICATE KEY UPDATE sql语句..语法:INSERT INTO table_name(a,b,c)VALUES(1,2,3),(4,5,6)ON DUPLICATE KEY UPDATE a = VALUES(A),b = VALUES(b),C = VALUES(c)中
用PHP我做到了这一点 . 使用分号,将其拆分为数组,然后通过循环提交 .
这应该达到你想要的 . 只需添加更多ID . 我测试过了 .
//你只是在php中构建它
因此,您可以使用一个查询更新孔表