You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL:如何基于双主键使用另一张表实现UPSERT?

实现双主键表的Upsert(更新+插入)操作

嘿,你要的其实是「Upsert」操作——也就是同时搞定已有数据更新和新数据插入,光用UPDATE肯定覆盖不了新增场景,得用数据库专门的语法来实现。不同数据库的写法略有差异,我给你分情况说清楚:

PostgreSQL 写法

PostgreSQL原生支持ON CONFLICT语法,刚好适配你的双主键场景:

INSERT INTO OLD_DATA (first_name, last_name, val_1, val_2, val_3, ...)
SELECT first_name, last_name, val_1, val_2, val_3, ...
FROM NEW_DATA
ON CONFLICT (first_name, last_name) DO UPDATE
SET val_1 = EXCLUDED.val_1,
    val_2 = EXCLUDED.val_2,
    val_3 = EXCLUDED.val_3,
    -- 把剩下的所有非主键字段都按这个格式补上
    ...;

这里的EXCLUDED是PostgreSQL的关键字,代表冲突时原本要插入的那条新数据,用它来赋值比再次关联NEW_DATA表更高效。

MySQL 写法

如果是MySQL,只要你的first_name和last_name已经被设为联合主键或者唯一索引,就可以用ON DUPLICATE KEY UPDATE:

INSERT INTO OLD_DATA (first_name, last_name, val_1, val_2, val_3, ...)
SELECT first_name, last_name, val_1, val_2, val_3, ...
FROM NEW_DATA
ON DUPLICATE KEY UPDATE
val_1 = VALUES(val_1),
val_2 = VALUES(val_2),
val_3 = VALUES(val_3),
-- 其他非主键字段依次补上
...;

VALUES(val_1)会取插入语句中对应字段的新值,逻辑和PostgreSQL的EXCLUDED类似。

SQL Server 写法

SQL Server用MERGE语法来实现Upsert,逻辑更直观:

MERGE INTO OLD_DATA AS target
USING NEW_DATA AS source
ON target.first_name = source.first_name AND target.last_name = source.last_name
WHEN MATCHED THEN
    UPDATE SET
        target.val_1 = source.val_1,
        target.val_2 = source.val_2,
        target.val_3 = source.val_3,
        -- 补上其他需要更新的字段
        ...
WHEN NOT MATCHED THEN
    INSERT (first_name, last_name, val_1, val_2, val_3, ...)
    VALUES (source.first_name, source.last_name, source.val_1, source.val_2, source.val_3, ...);

这段代码的逻辑很清晰:匹配到双主键就更新,没匹配到就插入。

几个重要注意事项

  • 一定要确保first_name和last_name在OLD_DATA表上被定义为主键或者唯一约束/索引,不然数据库没法检测冲突,Upsert会失效。
  • 字段比较多的话,别漏写任何需要插入或更新的字段,最好把所有非主键字段都明确列出来,避免出现默认值或NULL的意外问题。
  • 如果数据量特别大,建议分批执行操作,避免长时间锁表影响数据库性能。

内容的提问来源于stack exchange,提问作者user1367204

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:24:55