淺析PostgreSQL的 ON CONFLICT 和 upsert:不存在則插入/存在則更新、upsert 介紹、語法及示例


一、需求背景

  在數據庫表里,一般都有主鍵,主鍵是不能重復的,因為是唯一標識。假設這個時候需求來了,需要插入一組數據,這些數據中有些是完全新的,可以直接插入(insert),但有些主鍵內容是和原本表內的數據主鍵內容是一致的,這些就無法直接插入了,而是執行更新(update)操作。這時候就比較麻煩了,因為如果全部都是通過insert操作,必然會因為發現有重復唯一主鍵而報錯。

  一般來說,這時候需要通過業務代碼來進行判斷:有重復的主鍵值就執行更新操作,沒有就插入操作。但是PostgreSQL就提供了很好的解決方法,語法如下:

-- 1、主鍵id不重復就插入,否則更新
insert into 表名稱 (字段a, 字段b, ...) values (value_a, value_b, ...) on conflict (主鍵id) do update set ...略 -- 2、直接綁定主鍵名稱,主鍵重復則更新
insert into 表名稱 (字段a, 字段b, ...) values (value_a, value_b, ...) on conflict on constraint this_table_key do update set ...略

二、PostgreSQL 的 upsert 簡介

PostgreSQL 的 upsert 功能:當記錄不存在時,執行插入;否則,進行更新。

  在關系數據庫中,術語 upsert 被稱為合並(merge),意思是,當執行 INSERT 操作時,如果數據表中不存在對應的記錄,PostgreSQL 執行插入操作;如果數據表中存在對應的記錄,則執行更新操作。這就是為什么將其稱為 upsert(update or insert)的原因。

  通過 INSERT ON CONFLICT 來使用 upsert 功能:

INSERT INTO table_name(column_list) VALUES(value_list) ON CONFLICT target action;

1、target 可以是:

  • (column_name):一個字段名
  • ON CONSTRAINT constraint_name:其中的 constraint_name 可以是一個唯一約束的名字
  • WHERE predicate:帶謂語的 WHERE 子句

2、action 可以是:

  • DO NOTHING:當記錄存在時,什么都不做
  • DO UPDATE SET column_1 = value_1, … WHERE condition:當記錄存在時,更新表中的一些字段

注意,ON CONFLICT 只在 PostgreSQL 9.5 以上可用。

三、PostgreSQL 的 upsert 示例

-- 我們新建一個 customers 表來進行演示:
CREATE TABLE customers ( customer_id serial PRIMARY KEY, name VARCHAR UNIQUE, email VARCHAR NOT NULL, active bool NOT NULL DEFAULT TRUE ); -- customers 表有4個字段:customer_id、name、email 和 active。 -- 其中,name 字段有唯一約束,用於確保客戶的唯一性。
-- 下面,往 customers 表里插入幾行數據:
#SELECT * FROM customers; customer_id |   name    |         email         | active -------------+-----------+-----------------------+--------
          1 | IBM       | contact@ibm.com       | t 2 | Microsoft | contact@microsoft.com | t 3 | Intel     | contact@intel.com     | t (3 rows) ————————————————

  假設 Microsoft 更換了聯系方式 email:由 contact@microsoft.com 變成了 hotline@microsoft.com,我們可以使用 UPDATE 語句進行修改。然而,為了演示 upsert 功能,我們使用 INSERT ON CONFLICT 語句

INSERT INTO customers (NAME, email) VALUES ( 'Microsoft', 'hotline@microsoft.com' ) ON CONFLICT ON CONSTRAINT customers_name_key DO NOTHING;

  這個語句指明了,當數據存在時,什么都不做(DO NOTING)。下面的語句有一樣的效果,區別在於使用的是 name 字段,而不是約束的名字:

INSERT INTO customers (name, email) VALUES ( 'Microsoft', 'hotline@microsoft.com' ) ON CONFLICT (name) DO NOTHING;

  我們的目標是修改客戶的 email,所以應該用這條語句:

INSERT INTO customers (name, email) VALUES ( 'Microsoft', 'hotline@microsoft.com' ) ON CONFLICT (name) DO UPDATE
   SET email = EXCLUDED.email; upsert

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM