跳转到内容

Merge (SQL)

维基百科,自由的百科全书

关系数据库管理系统使用SQLMERGE语句(也被称为upsert)来处理数据:它根据特定的匹配条件,决定是插入(INSERT)新记录,还是更新(UPDATE)或删除(DELETE)现有记录。该语句在SQL:2003英语SQL:2003标准中被正式引入,并在SQL:2008英语SQL:2008标准中得到了进一步扩展。

用法

[编辑]
MERGE INTO tablename USING table_reference ON (condition)
  WHEN MATCHED THEN
    UPDATE SET column1 = value1 [, column2 = value2 ...]
  WHEN NOT MATCHED THEN
    INSERT (column1 [, column2 ...]) VALUES (value1 [, value2 ...]);

MERGE语句在目标表(INTO表)和源表(USING表/视图/子查询)之间执行右连接(Right Join)——其中目标表为左表,源表为右表。四种可能的组合产生了以下规则:

  • 源表中有,目标表中也有(ON条件匹配):执行UPDATE
  • 源表中有,目标表中没有(ON条件不匹配):执行INSERT
  • 源表中没有,目标表中有:不执行任何操作。
  • 源表和目标表中都没有:不执行任何操作。

注意:根据SQL:2003英语SQL:2003标准,如果多个源表行匹配同一个目标表行,必须报错。你不能使用一条MERGE语句多次更新同一行目标表数据。

实现情况

[编辑]

PostgreSQL[1]OracleDB2SQL Server等主流数据库均支持标准语法。

同义词

[编辑]

一些数据库实现采用了Upsert(Update和Insert的混成词)这一术语,指代“如果记录不存在则插入,如果已存在则更新”的数据库语句或组合。PostgreSQL (v9.5+)[2]SQLite(v3.24+)[3]Microsoft Azure SQL Database[4]均使用此术语。

SQL:2003英语SQL:2003标准定义了MERGE 语句,用以提供类似的功能。

通常情况下,数据库操作运行在多个代理(Agent/进程)同时对同一个数据库执行查询的环境中。如果数据库管理系统(DBMS)本身不支持原生版本的UPSERT或MERGE,则该操作应当封装在一个事务(Transaction)中,以确保其隔离性(Isolation)和原子性(Atomicity)。

其他非标准实现

[编辑]

MySQL中,UPSERT操作是通过INSERT ... ON DUPLICATE KEY UPDATE语法实现的(即:如果行已存在,则执行更新操作)[5]。但限制是连接必须基于主键或唯一索引。此外还支持>REPLACE INTO(先删再插)[6],即首先尝试进行插入操作;如果插入失败,则删除已存在的行(若存在),最后再插入新记录。还支持INSERT IGNORE[7],告知服务器忽略“重复键(duplicate key)”错误并继续执行(即:现有的行不会被插入或更新,但所有新的行都会被正常插入)。

SQLite:支持INSERT OR REPLACE INTO。还支持REPLACE INTO作为兼容MySQL的别名。[8]

Firebird支持MERGE INTO。还支持单行版本的UPDATE OR INSERT INTO tablename (columns) VALUES (values) [MATCHING (columns)],但后者无法在插入和更新时采取不同的操作(例如仅为新行设置序列值)。

IBM DB2:扩展了多个WHEN MATCHEDWHEN NOT MATCHED子句,并支持通过... AND some-condition条件进行细分过滤。

Microsoft SQL Server:支持通过 WHEN NOT MATCHED BY SOURCE 来处理源表中不存在但目标表中存在的行(即支持了左连接语义)。

PostgreSQL自第15版本起开始支持MERGE语句,但在此之前,它通过INSERT INTO ... ON CONFLICT [ conflict_target ] conflict_action.[9]语法来支持合并操作。

CUBRID支持MERGE INTO语句[10],同时也支持使用INSERT ... ON DUPLICATE KEY UPDATE语法[11]。为了兼容MySQL,它还支持REPLACE INTO[12]

Apache Phoenix英语Apache Phoenix支持UPSERT VALUES[13]UPSERT SELECT[14]语法。

Spark SQL在操作中支持UPDATE SET *INSERT *子句。[15]

Apache Impala英语Apache Impala支持UPSERT INTO ... SELECT语法。[16]

在NoSQL中的应用

[编辑]

类似的概念也应用于某些NoSQL数据库中。

MongoDB中,可以通过update操作更新与键相关联的值中的字段。如果找不到该键,update操作会报错。但在update操作中可以设置upsert标志:在这种情况下,如果键不存在,则存储一个与给定键关联的新值;否则,整个值将被替换。

Redis中,SET操作用于设置与给定键关联的值。由于Redis不了解该值内部结构的任何细节,因此“更新(update)”操作没有意义。所以SET操作始终具有“设置或替换(set or replace)”的语义。

参考文献

[编辑]
  1. ^ E.1. Release 15. PostgreSQL Documentation. 13 October 2022 [13 October 2022]. (原始内容存档于13 October 2022) (英语). 
  2. ^ PostgreSQL Upsert Using INSERT ON CONFLICT statement. PostgreSQL Tutorial. (原始内容存档于Nov 28, 2022). 
  3. ^ "upsert页面存档备份,存于互联网档案馆)", SQLite, visited 6-6-2018.
  4. ^ MERGE (Transact-SQL). Transact-SQL Reference (Database Engine). Microsoft Learn. (原始内容存档于Jun 24, 2016). 
  5. ^ MySQL :: MySQL 5.1 Reference Manual :: 12.2.4.3 INSERT ... ON DUPLICATE KEY UPDATE Syntax
  6. ^ MySQL 5.1 Reference Manual: 11.2.6 REPLACE Syntax. [2026-03-13]. (原始内容存档于2016-05-06). 
  7. ^ MySQL 5.5 Reference Manual :: 13.2.5 INSERT Syntax. [29 October 2013]. (原始内容存档于2013-10-24). 
  8. ^ SQL As Understood By SQLite: INSERT. [2012-09-27]. (原始内容存档于2012-09-23). 
  9. ^ PostgreSQL INSERT page. [2026-03-13]. (原始内容存档于2016-12-28). 
  10. ^ New CUBRID 9.0.0. CUBRID Official Blog. 2012-10-30 [2012-11-08]. (原始内容存档于2012-11-05). 
  11. ^ CUBRID :: Data Manipulation Statements :: Insert :: ON DUPLICATE KEY UPDATE Clause. [2026-03-13]. (原始内容存档于2016-10-07). 
  12. ^ CUBRID :: Data Manipulation Statements :: Replace. [2026-03-13]. (原始内容存档于2016-10-07). 
  13. ^ UPSERT VALUES. [2026-03-13]. (原始内容存档于2016-12-27). 
  14. ^ UPSERT SELECT. [2026-03-13]. (原始内容存档于2016-12-27). 
  15. ^ MERGE INTO (Delta Lake on Databricks). [2026-03-13]. (原始内容存档于2022-10-01). 
  16. ^ UPSERT Statement (Apache Impala Documentation). [2026-03-13]. (原始内容存档于2025-02-20). 

外部链接

[编辑]