PostgreSQL 的 upsert 簡介
在關(guān)系數(shù)據(jù)庫中厢拭,術(shù)語 upsert 被稱為合并(merge)兰英。意思是,當(dāng)執(zhí)行 INSERT 操作時(shí)供鸠,如果數(shù)據(jù)表中不存在對(duì)應(yīng)的記錄畦贸,PostgreSQL 執(zhí)行插入操作;如果數(shù)據(jù)表中存在對(duì)應(yīng)的記錄楞捂,則執(zhí)行更新操作薄坏。這就是為什么將其稱為 upsert(update or insert)的原因。
通過 INSERT ON CONFLICT 來使用 upsert 功能:
INSERT INTO table_name(column_list) VALUES(value_list)
ON CONFLICT target action;
target 可以是:
(column_name):一個(gè)字段名
ON CONSTRAINT constraint_name:其中的 constraint_name 可以是一個(gè)唯一約束的名字
WHERE predicate:帶謂語的 WHERE 子句
action 可以是:
DO NOTHING:當(dāng)記錄存在時(shí)寨闹,什么都不做
DO UPDATE SET column_1 = value_1, … WHERE condition:當(dāng)記錄存在時(shí)胶坠,更新表中的一些字段
注意,ON CONFLICT 只在 PostgreSQL 9.5 以上可用繁堡。
PostgreSQL 的 upsert 示例
我們新建一個(gè) customers 表來進(jìn)行演示:
CREATE TABLE customers (
customer_id serial PRIMARY KEY,
name VARCHAR UNIQUE,
email VARCHAR NOT NULL,
active bool NOT NULL DEFAULT TRUE
);
customers 表有4個(gè)字段:customer_id沈善、name乡数、email 和 active。其中闻牡,name 字段有唯一約束净赴,用于確保客戶的唯一性罩润。
upsert
下面玖翅,往 customers 表里插入幾行:
INSERT INTO customers (NAME, email)
VALUES
('IBM', 'contact@ibm.com'),
(
'Microsoft',
'contact@microsoft.com'
),
(
'Intel',
'contact@intel.com'
);
#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)
————————————————
假設(shè) Microsoft 更換了聯(lián)系方式 email:由 contact@microsoft.com 變成了 hotline@microsoft.com,我們可以使用 UPDATE 語句進(jìn)行修改哨啃。然而烧栋,為了演示 upsert 功能,我們使用 INSERT ON CONFLICT 語句:
INSERT INTO customers (NAME, email)
VALUES
(
'Microsoft',
'hotline@microsoft.com'
)
ON CONFLICT ON CONSTRAINT customers_name_key
DO NOTHING;
這個(gè)語句指明了拳球,當(dāng)數(shù)據(jù)存在時(shí)审姓,什么都不做(DO NOTING)。下面的語句有一樣的效果祝峻,區(qū)別在于使用的是 name 字段魔吐,而不是約束的名字:
INSERT INTO customers (name, email)
VALUES
(
'Microsoft',
'hotline@microsoft.com'
)
ON CONFLICT (name)
DO NOTHING;
我們的目標(biāo)是修改客戶的 email,所以應(yīng)該用這條語句:
INSERT INTO customers (name, email)
VALUES
(
'Microsoft',
'hotline@microsoft.com'
)
ON CONFLICT (name)
DO
UPDATE
SET email = EXCLUDED.email;