UPSERT:ON CONFLICT DO UPDATE(PostgreSQL)
使用 ON CONFLICT DO UPDATE 实现幂等插入,使用 EXCLUDED,并选择正确的冲突目标。
UPSERT:ON CONFLICT DO UPDATE(PostgreSQL) 是 CoddyKit 上的免费 SQL Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 SQL Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 SQL Academy 课程共包含 4 节课。
什么是 UPSERT
UPSERT = 不存在时执行 INSERT,存在时执行 UPDATE。PostgreSQL 将其写作 INSERT ... ON CONFLICT。
ON CONFLICT DO NOTHING
不存在时插入,重复时静默跳过:
INSERT INTO users (email, full_name)
VALUES ('alice@example.com', 'Alice')
ON CONFLICT (email) DO NOTHING;ON CONFLICT DO UPDATE
不存在时插入,否则更新指定的列:
INSERT INTO users (email, full_name, last_login)
VALUES ('alice@example.com', 'Alice', NOW())
ON CONFLICT (email)
DO UPDATE SET
full_name = EXCLUDED.full_name,
last_login = EXCLUDED.last_login;EXCLUDED:提议插入的行
在 DO UPDATE 中,EXCLUDED.col 表示“INSERT 尝试写入的值”。不带限定的列名(或 users.col)表示现有行中的值。
ON CONFLICT (email)
DO UPDATE SET visits = users.visits + 1,
last_seen = EXCLUDED.last_seen;冲突目标
您必须指定一个唯一约束或主键:
ON CONFLICT (email) -- column with UNIQUE
ON CONFLICT (user_id, day) -- composite UNIQUE
ON CONFLICT ON CONSTRAINT users_email_key -- by name有条件的 UPSERT(DO UPDATE 中的 WHERE)
仅在满足条件时更新:
INSERT INTO inventory (product_id, qty)
VALUES (42, 5)
ON CONFLICT (product_id)
DO UPDATE SET qty = inventory.qty + EXCLUDED.qty
WHERE inventory.qty + EXCLUDED.qty <= 1000;多行 UPSERT
插入多行;每一行都会单独处理:
INSERT INTO page_views (path, day, count)
VALUES ('/home', CURRENT_DATE, 1), ('/about', CURRENT_DATE, 1)
ON CONFLICT (path, day)
DO UPDATE SET count = page_views.count + EXCLUDED.count;UPSERT 中的 RETURNING
返回最终的行(无论是插入还是更新得到的):
INSERT INTO users (email, full_name)
VALUES ('alice@example.com', 'Alice')
ON CONFLICT (email) DO UPDATE
SET full_name = EXCLUDED.full_name
RETURNING id, full_name;幂等工作流
UPSERT 使重试变得安全。如果您的 webhook 触发了两次,第二次调用会更新同一行,而不是创建重复数据。
MERGE(SQL 标准,PG15+)
PostgreSQL 15 增加了符合 SQL 标准的 MERGE,可以在一条语句中执行 INSERT、UPDATE 和 DELETE:
MERGE INTO users AS u
USING (VALUES ('alice@example.com','Alice')) AS src(email, name)
ON u.email = src.email
WHEN MATCHED THEN UPDATE SET full_name = src.name
WHEN NOT MATCHED THEN INSERT (email, full_name) VALUES (src.email, src.name);何时不应使用 UPSERT
UPSERT 需要唯一约束。如果没有唯一约束,通常应先执行一次 SELECT,然后执行 INSERT 或 UPDATE——但要注意竞态条件;请在事务中配合适当的锁定来执行。
回顾
ON CONFLICT 是 PostgreSQL 简洁且原子的 UPSERT 方式。
- 使用 DO NOTHING 实现“缺少时插入”
- 使用 DO UPDATE 实现真正的 UPSERT
EXCLUDED= 提议插入的行- 始终指定冲突目标
快速检查
在 ON CONFLICT (email) DO UPDATE SET last_login = EXCLUDED.last_login 中,EXCLUDED 指的是什么?
常见问题解答
「UPSERT:ON CONFLICT DO UPDATE(PostgreSQL)」课时是免费的吗?
是的 — 「UPSERT:ON CONFLICT DO UPDATE(PostgreSQL)」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 SQL Academy 课程的其余内容,请升级到 CoddyKit PRO。 SQL Academy 课程共包含 4 节课。
「UPSERT:ON CONFLICT DO UPDATE(PostgreSQL)」这节课中我会学到什么?
使用 ON CONFLICT DO UPDATE 实现幂等插入,使用 EXCLUDED,并选择正确的冲突目标。 你通过在浏览器中直接运行的动手代码来练习 SQL Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 SQL Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 SQL Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。
「UPSERT:ON CONFLICT DO UPDATE(PostgreSQL)」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 SQL Academy 课中编写并运行代码吗?
能。每节 SQL Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 使用多行 INSERT
- UPSERT:ON CONFLICT DO UPDATE(PostgreSQL)
- 使用 FROM 的 UPDATE 与连接式更新
- 使用 USING 的 DELETE 与安全模式