基本语法
sqlsql复制INSERT INTO table_name (column1, column2, ...)
VALUES (value1, value2, ...)
ON CONFLICT (conflict_target) DO UPDATE
SET column1 = value1, column2 = value2, ...;
参数说明
conflict_target - 定义冲突检测的条件,可以是:
DO UPDATE SET - 指定冲突时要更新的列和值
常见用法示例
1. 基于主键的 Upsert
INSERT INTO users (id, name, email)
VALUES (1,John Doe,john@example.com)
ON CONFLICT (id) DO UPDATE
SET name = EXCLUDED.name, email = EXCLUDED.email;
2. 使用约束名称
INSERT INTO products (sku, name, price)
VALUES (ABC123,Widget, 9.99)
ON CONFLICT ON CONSTRAINT products_sku_key DO UPDATE
SET name = EXCLUDED.name, price = EXCLUDED.price;
3. 部分更新(只更新特定字段)
INSERT INTO orders (order_id, customer_id, total)
VALUES (1001, 42, 199.99)
ON CONFLICT (order_id) DO UPDATE
SET total = EXCLUDED.total;
4. 使用 EXCLUDED 伪表引用新值
INSERT INTO inventory (product_id, quantity)
VALUES (101, 5)
ON CONFLICT (product_id) DO UPDATE
SET quantity = inventory.quantity + EXCLUDED.quantity;
5. 条件更新
INSERT INTO articles (id, title, views)
VALUES (123,New Article, 1)
ON CONFLICT (id) DO UPDATE
SET views = articles.views + 1
WHERE articles.title = EXCLUDED.title;
特殊用法
6. 多列唯一约束
INSERT INTO user_devices (user_id, device_id, last_active)
VALUES (1,mobile, NOW())
ON CONFLICT (user_id, device_id) DO UPDATE
SET last_active = EXCLUDED.last_active;
7. 什么都不做(类似 MySQL 的 INSERT IGNORE)
INSERT INTO table_name (id, data)
VALUES (1,test)
ON CONFLICT (id) DO NOTHING;
注意事项
必须指定冲突目标(主键、唯一约束或约束名称)
EXCLUDED
伪表提供了被拒绝的插入行的值
性能通常优于先查询再决定插入或更新
在事务中使用时,整个操作是原子的
PostgreSQL 9.5 及以上版本支持此语法
与 MySQL REPLACE 的区别
MySQL 的 REPLACE INTO
实际上是先删除冲突行再插入新行,而 PostgreSQL 的 ON CONFLICT DO UPDATE
是真正的更新操作,保留原有行的其他字段值。
评论