跳至內容

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). 

外部連結

[編輯]