7种数据库(MySQL/Oracle/SqlServer/PostgreSQL/达梦/人大金仓/南大通用)的存在则更新,不存在则插入(UPSERT)SQL写法
在工作中遇到了这么一个需求,在往数据库插入数据时,如果一条数据不存在则插入,如果存在(根据主键或唯一索引判断)则更新,也就是所谓的UPSERT操作。大部分数据库都没有UPSERT语句,不过他们都有一些SQL的写法来实现这样的操作。
1. MySQL
使用ON DUPLICATE KEY UPDATE,如果要插入这条数据将导致唯一索引冲突或主键冲突,则会对原有数据进行UPDATE操作,否则进行INSERT操作。
假设表t1中a是主键,如:
INSERT INTO t1 (a,b,c) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE c=c+1;
UPDATE后可以接多个列,如:
INSERT INTO t1 (a,b,c) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE b=2, c=3;
对于多行数据可以这么写(采用别名):
INSERT INTO t1 (a,b,c) VALUES (1,2,3),(4,5,6) AS new
ON DUPLICATE KEY UPDATE c = new.a+new.b;
注:如果没有主键或唯一索引,每次都会INSERT,永远不会UPDATE。
如果表中有多个唯一索引,并且有多行都匹配上了,也只会更新一行,所以不要在有多个唯一索引的表中使用ON DUPLICATE KEY UPDATE。
2. Oracle
使用MERGE INTO,根据给定的列的值来决定INSERT还是UPDATE,用于判断的列可以不是主键。
MERGE INTO ALERT_INFO
USING DUAL
ON (ALERT_INFO.ID = '7')
WHEN NOT MATCHED
THEN
INSERT (ID,CONTENT) VALUES ('7','A7')
WHEN MATCHED
THEN
UPDATE SET CONTENT = 'A7';
MERGE INTO ALERT_INFO
USING DUAL
ON (ALERT_INFO.CONTENT = 'AA6')
WHEN NOT MATCHED
THEN
INSERT (ID,CONTENT) VALUES ('6','AA5')
WHEN MATCHED
THEN
UPDATE SET ID = '6';
3. SqlServer
使用MERGE INTO,根据给定的列的值来决定INSERT还是UPDATE,用于判断的列可以不是主键。
注:官方文档说这种用法可能带来并发问题。
MERGE INTO xh.dbo.hhhh AS tgt
USING (VALUES ('Recommendation222',111), ('Review222', 211),
('Internet', 311))
as src (NewName, NewReasonType)
ON tgt.aaa = src.NewName
WHEN MATCHED THEN
UPDATE SET bbb = src.NewReasonType
WHEN NOT MATCHED BY TARGET THEN
INSERT (aaa, bbb) VALUES (NewName, NewReasonType);
4. PostgreSQL
指定主键/唯一索引的列决定INSERT还是UPDATE
注:官方文档说这种用法是原子的
假设在public这个schema下的表student中,id是主键
INSERT INTO public.student (id, name, description)
VALUES (5, 'Gizmo Transglobal', 'xxx'), (6, 'Associated Computing, Inc', 'xxxxx')
ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, description=EXCLUDED.description;
5. 达梦(DM)
使用MERGE INTO,根据给定的列的值来决定INSERT还是UPDATE,用于判断的列可以不是主键。
与Oracle语法相同
MERGE INTO ALERT_INFO
USING DUAL
ON (ALERT_INFO.ID = '1')
WHEN NOT MATCHED
THEN
INSERT (ID,CONTENT) VALUES ('1','A1')
WHEN MATCHED
THEN
UPDATE SET CONTENT = 'A1';
MERGE INTO ALERT_INFO
USING DUAL
ON (ALERT_INFO.CONTENT = 'AA6')
WHEN NOT MATCHED
THEN
INSERT (ID,CONTENT) VALUES ('6','AA5')
WHEN MATCHED
THEN
UPDATE SET ID = '6';
6. 人大金仓(KingBase)
使用MERGE INTO,根据给定的列的值来决定INSERT还是UPDATE,用于判断的列可以不是主键。
与Oracle语法相同
MERGE INTO ALERT_INFO
USING DUAL
ON (ALERT_INFO.ID = '1')
WHEN NOT MATCHED
THEN
INSERT (ID,CONTENT) VALUES ('1','A1')
WHEN MATCHED
THEN
UPDATE SET CONTENT = 'A1';
MERGE INTO ALERT_INFO
USING DUAL
ON (ALERT_INFO.CONTENT = 'AA6')
WHEN NOT MATCHED
THEN
INSERT (ID,CONTENT) VALUES ('6','AA5')
WHEN MATCHED
THEN
UPDATE SET ID = '6';
7. 南大通用(GBase8s)
使用MERGE INTO,根据给定的列的值来决定INSERT还是UPDATE,用于判断的列可以不是主键。
与Oracle语法相同
MERGE INTO ALERT_INFO
USING DUAL
ON (ALERT_INFO.ID = '1')
WHEN NOT MATCHED
THEN
INSERT (ID,CONTENT) VALUES ('1','A1')
WHEN MATCHED
THEN
UPDATE SET CONTENT = 'A1';
MERGE INTO ALERT_INFO
USING DUAL
ON (ALERT_INFO.CONTENT = 'AA6')
WHEN NOT MATCHED
THEN
INSERT (ID,CONTENT) VALUES ('6','AA5')
WHEN MATCHED
THEN
UPDATE SET ID = '6';
更详细的介绍请进入参考资料中的官方文档查看
参考资料:
MySQL官方文档:
https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html
Oracle官方文档:
https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/MERGE.html#GUID-5692CCB7-24D9-4C0E-81A7-A22436DC968F
SqlServer官方文档:
https://learn.microsoft.com/zh-cn/sql/t-sql/statements/merge-transact-sql?view=sql-server-ver16
PostgreSQL官方文档:
https://www.postgresql.org/docs/15/sql-insert.html
达梦官方文档:
https://eco.dameng.com/document/dm/zh-cn/sql-dev/practice-dml-operation.html
人大金仓官方文档:
https://help.kingbase.com.cn/v8/development/sql-plsql/sql/SQL_Statements_10.html#merge
南大通用官方文档:
https://cdn.gbase.cn/products/27/b--vfeeESpHTsMJy2SZ0Y-GBase 8s V8.8 SQL 指南:语法.pdf