Oracle通过mergeinto实现存在更新、不存在插入,但更新时不能修改关联条件字段;MySQL通过insertinto...onduplicatekeyupdate,依赖唯一索引触发更新,无此限制。两者语法差异显著,需注意约束差异,根据数据库特性选择合适写法,避免数据不一致,并考虑不同场景。
Oracle和MySQL批量插入或更新方法(insertOrUpdateBatch)
时间:2026-07-18
浏览:102
文章目录
在关系型数据库中,SQL 语言存在明显的“方言”差异。Oracle 和 MySQL 虽然都是主流关系型数据库,但在实现“存在则更新,不存在则插入”(即 upsert)这类逻辑时,语法差异较大,稍不注意就容易出错。本文系统梳理两个数据库的典型写法,帮助开发者快速理解并避免常见问题。

1. Oracle 数据库
Oracle 实现“插入或更新”(upsert)的经典方案是 MERGE INTO 语句。其核心逻辑是:将源数据(或临时数据)与目标表进行匹配,匹配成功则执行更新,匹配失败则执行插入。需要注意的是,更新时不能修改关联条件中使用的字段(如主键或联合主键),否则会触发异常。
-- MERGE INTO 语法,当数据存在时更新数据,不能更新指定主键字段(判断数据是否存在的字段)
MERGE INTO QWPH_XN.SYS_AREA t1
USING (SELECT 'lkz001' AS ID, 'KD001' AS P_ID FROM DUAL) t2
ON (t1.ID = t2.ID AND t1.P_ID = t2.P_ID)
WHEN MATCHED THEN
UPDATE SET t1.AREA_NAME = 'lkz0016666666666666666666'
WHEN NOT MATCHED THEN
INSERT (ID, P_ID) VALUES ('lkz002', 'KD001');
-- 另一种写法:直接使用 DUAL 作为源
MERGE INTO QWPH_XN.SYS_AREA t1
USING DUAL
ON (t1.ID = 'lkz003')
WHEN MATCHED THEN
UPDATE SET t1.AREA_NAME = 'KEDONG'
WHEN NOT MATCHED THEN
INSERT (ID, P_ID) VALUES ('lkz003', 'KD003');
第一个示例通过 DUAL 构造临时数据,第二个示例直接以 DUAL 为源,配合 ON 条件中的固定值进行匹配。在实际项目中,更常见的是在 MyBatis 的 XML 中编写批量操作,例如:
MERGE INTO ${model}.SYS_AREA t1 USING DUAL ON (t1.ID = #{entity.id} AND t1.P_ID = #{entity.pId}) WHEN MATCHED THEN UPDATE WHEN NOT MATCHED THEN INSERT (ID, AREA_NAME, P_ID, DTYPE, "LEVEL", DATASOURCE_ID) VALUES (#{entity.id}, #{entity.areaName}, #{entity.pId}, #{entity.level}, #{entity.dtype}, #{entity.datasourceId}) AREA_NAME = #{entity.areaName}, DTYPE = #{entity.dtype}, LEVEL = #{entity.level}, DATASOURCE_ID = #{entity.datasourceId},
该写法通过 foreach 循环拼接多个 MERGE INTO 语句,每条语句以分号结尾。注意:ON 条件中的字段(如 ID 和 P_ID)在 UPDATE 部分不可修改,否则会报错。若业务需要更新这些字段,则本质上属于插入新记录。
2. MySQL 数据库
MySQL 的语法与 Oracle 完全不同,它使用 INSERT INTO ... ON DUPLICATE KEY UPDATE。该语法的触发条件是:插入的数据与表中已有的主键或唯一索引冲突时,执行更新操作;若无冲突,则正常插入。
INSERT INTO TASK_LOG (TASK_ID, TASK_NAME, EXEC_TYPE, STATUS, EXEC_TIME, EXCEPTION_MESSAGE) VALUES (#{entity.taskId}, #{entity.taskName}, #{entity.execType}, #{entity.status}, #{entity.execTime}, #{entity.exceptionMessage}) ON DUPLICATE KEY UPDATE TASK_ID = VALUES(TASK_ID), TASK_NAME = VALUES(TASK_NAME), EXEC_TYPE = VALUES(EXEC_TYPE), STATUS = VALUES(STATUS), EXEC_TIME = VALUES(EXEC_TIME), EXCEPTION_MESSAGE = VALUES(EXCEPTION_MESSAGE)
在上述 MyBatis 示例中,ON DUPLICATE KEY UPDATE 后面列出需要更新的字段,通常通过 VALUES(字段名) 引用准备插入的新值。注意:目标表必须至少有一个唯一索引(主键或 Unique 约束),否则该语句将退化为普通插入,无法触发更新。
总结
两个数据库的“upsert”实现思路不同:Oracle 依赖 MERGE INTO,MySQL 依赖 ON DUPLICATE KEY UPDATE。编写代码时,除了要掌握具体语法,还需注意关联字段的约束差异——Oracle 不允许更新匹配条件中的字段,MySQL 则无此限制,但必须依赖唯一索引。此外,在批量操作方面,Oracle 使用 foreach 拼接时需注意分号分隔,而 MySQL 的批量写法更为简洁,直接使用 VALUES 列表即可。理解这些差异,有助于在跨数据库迁移或编写通用代码时减少错误。
实用工具推荐
绿化、压缩、噪点和虚拟水印,自由调节做旧程度。
选择画质和输出格式,预览压缩前后的大小。