Cx_Oracle操作Oracle:实现类似ON DUPLICATE KEY UPDATE的功能问询
Oracle实现UPSERT(新增/替换)的无中间表方案
嘿,这个问题我太熟悉了!Oracle里确实有替代MySQL ON DUPLICATE KEY UPDATE的方案,完全不用建中间表就能直接搞定「存在则更新,不存在则插入」的需求,最常用的就是MERGE语句,兼容性拉满,几乎所有Oracle版本都支持,另外Oracle 12cR2+还有更简洁的写法,我给你详细拆解下:
一、通用方案:MERGE语句(全Oracle版本兼容)
MERGE是Oracle原生的UPSERT语法,核心逻辑就是把你要插入的数据和目标表做匹配,根据是否存在重复记录来执行更新或插入操作。
步骤1:确保表有唯一约束
首先得给表A定义「重复判断规则」,比如你要根据SID+DATE+ATT这三个字段判断是否重复,那先给表加个唯一约束:
ALTER TABLE A ADD CONSTRAINT A_UPSERT_UNIQUE UNIQUE (SID, "DATE", ATT);
步骤2:用executemany执行MERGE批量操作
把你的Data元组列表直接传入MERGE语句的绑定变量,不用中间表:
# 构造MERGE语句 upsert_sql = ''' MERGE INTO A target USING (SELECT :1 AS SID, :2 AS "DATE", :3 AS ATT, :4 AS VALUE FROM dual) source -- 这里的条件就是判断记录是否重复的唯一键规则 ON (target.SID = source.SID AND target."DATE" = source."DATE" AND target.ATT = source.ATT) WHEN MATCHED THEN -- 匹配到重复记录时,更新指定字段(这里更新VALUE,你可以加更多字段) UPDATE SET target.VALUE = source.VALUE WHEN NOT MATCHED THEN -- 没匹配到就插入新记录 INSERT (SID, "DATE", ATT, VALUE) VALUES (source.SID, source."DATE", source.ATT, source.VALUE) ''' # 用executemany批量执行 cur.executemany(upsert_sql, Data) # 别忘了提交事务 conn.commit()
这样就直接完成了批量UPSERT,完全不需要中间表B,是不是比之前的方法高效多了?
二、简化方案:Oracle 12cR2+的INSERT ... ON DUPLICATE KEY UPDATE等价写法
如果你用的是Oracle 12cR2及以上版本,还可以用更贴近MySQL语法的简化写法,不过本质还是基于MERGE的封装:
upsert_sql = ''' INSERT INTO A (SID, "DATE", ATT, VALUE) VALUES (:1, :2, :3, :4) ON DUPLICATE KEY UPDATE VALUE = :4 ''' cur.executemany(upsert_sql, Data) conn.commit()
不过要注意,这个语法需要表已经有主键或唯一约束,否则会报错。
几个注意事项:
- 唯一约束是核心:不管用哪种方法,都必须先定义好判断重复的唯一键,不然数据库不知道怎么识别重复记录。
- 绑定变量顺序要对应:Data里的元组顺序要和SQL里的
:1、:2等绑定变量顺序完全一致。 - 多字段更新:如果需要更新多个字段,在MERGE的
UPDATE SET后面加逗号分隔就行,比如UPDATE SET target.VALUE = source.VALUE, target.UPDATE_TIME = SYSDATE。
内容的提问来源于stack exchange,提问作者Arthur Yang
相关产品推荐
相关产品推荐

