MySQL 8 如何实现不存在则插入、存在时仅满足条件才更新的批量操作
MySQL8 批量条件更新插入实现方案
核心思路
INSERT ... ON DUPLICATE KEY UPDATE 无需显式WHERE子句,只需在UPDATE赋值逻辑中加入条件判断,即可实现等价的条件更新效果,且完全支持批量插入场景,性能远优于循环单条操作。
执行逻辑完全匹配需求:
- 主键不存在时:直接插入新行,不受条件约束
- 主键冲突时:通过判断原行的
task_status字段,仅当其值为0时更新对应字段,否则赋值为原行旧值(MySQL检测到值无变化时不会实际修改该行),天然实现task_status=1后completed_on永久锁定的效果。
具体SQL实现
MySQL 8.0.19及以上推荐写法(兼容长期版本)
采用插入行别名代替官方后续将废弃的VALUES()函数:
INSERT INTO taskStatus (task_id, employee_id, completed_on, task_status) -- 批量替换为实际要插入的多行业务数据 VALUES (101, 1, '2024-05-20 10:00:00', b'0'), (102, 2, '2024-05-20 11:00:00', b'1'), (103, 1, '2024-05-20 12:00:00', b'0') AS new_data ON DUPLICATE KEY UPDATE -- 仅原行task_status为0时更新completed_on,否则保留原值 completed_on = IF(task_status = b'0', new_data.completed_on, completed_on), -- 如需锁定task_status=1的行不被任何更新修改,可添加下述规则 task_status = IF(task_status = b'0', new_data.task_status, task_status);
低版本兼容写法(支持所有MySQL版本)
INSERT INTO taskStatus (task_id, employee_id, completed_on, task_status) VALUES (101, 1, '2024-05-20 10:00:00', b'0'), (102, 2, '2024-05-20 11:00:00', b'1'), (103, 1, '2024-05-20 12:00:00', b'0') ON DUPLICATE KEY UPDATE completed_on = IF(task_status = b'0', VALUES(completed_on), completed_on), task_status = IF(task_status = b'0', VALUES(task_status), task_status);
批量处理优化建议
- 单次批量插入行数控制在1000-5000之间,避免大事务和长锁等待问题
- 处理超大量数据时按批次拆分执行上述SQL,避免一次性锁定过多行
内容的提问来源于stack exchange,提问作者nantitv
相关产品推荐
相关产品推荐

