test03=# insert into test values (1,'test',now()) on conflict (id) do update set info=excluded.info,crt_time=excluded.crt_time; INSERT 0 1

简介: PostgreSQL 9.5 引入原生 UPSERT(INSERT ON CONFLICT),支持冲突时 DO NOTHING 或 DO UPDATE,原子性处理“存在即更新、不存在即插入”,大幅提升并发安全与代码简洁性,替代了此前需函数或 CTE 实现的复杂方案。(239字)

PostgreSQL 9.5 引入了一项新功能,UPSERT(insert on conflict do),当插入遇到约束错误时,直接返回,或者改为执行UPDATE。

语法如下

Command: INSERT
Description: create new rows in a table
Syntax:
[ WITH [ RECURSIVE ] with_query [, ...] ]
INSERT INTO table_name [ AS alias ] [ ( column_name [, ...] ) ]
{ DEFAULT VALUES | VALUES ( { expression | DEFAULT } [, ...] ) [, ...] | query }
[ ON CONFLICT [ conflict_target ] conflict_action ]
[ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ]

where conflict_target can be one of:

( { index_column_name | ( index_expression ) } [ COLLATE collation ] [ opclass ] [, ...] ) [ WHERE index_predicate ]  
ON CONSTRAINT constraint_name  

and conflict_action is one of:

DO NOTHING  
DO UPDATE SET { column_name = { expression | DEFAULT } |  
                ( column_name [, ...] ) = ( { expression | DEFAULT } [, ...] ) |  
                ( column_name [, ...] ) = ( sub-SELECT )  
              } [, ...]  
          [ WHERE condition ]  

PostgreSQL 9.5以前的版本,可以通过函数,或者with语法来实现UPSERT类似的功能。

9.5+ UPSERT用法举例
创建一张测试表,其中一个字段为唯一键或者主键。

create table test(id int primary key, info text, crt_time timestamp);

  1. 不存在则插入,存在则更新

test03=# insert into test values (1,'test',now()) on conflict (id) do update set info=excluded.info,crt_time=excluded.crt_time;
INSERT 0 1

test03=# select * from test;
id | info | crt_time
----+------+----------------------------
1 | test | 2017-04-24 15:27:25.393948
(1 row)

test03=# insert into test values (1,'hello digoal',now()) on conflict (id) do update set info=excluded.info,crt_time=excluded.crt_time;
INSERT 0 1

test03=# select * from test;
id | info | crt_time
----+--------------+----------------------------
1 | hello digoal | 2017-04-24 15:27:39.140877
(1 row)

  1. 不存在则插入,存在则直接返回(不做任何处理)

test03=# insert into test values (1,'hello digoal',now()) on conflict (id) do nothing;
INSERT 0 0
test03=# insert into test values (1,'pu',now()) on conflict (id) do nothing;
INSERT 0 0
test03=# insert into test values (2,'pu',now()) on conflict (id) do nothing;
INSERT 0 1
test03=# select * from test;
id | info | crt_time
----+--------------+----------------------------
1 | hello digoal | 2017-04-24 15:27:39.140877
2 | pu | 2017-04-24 15:28:20.37392
(2 rows)
9.5- UPSERT用法举例
用户可以根据实际需求,使用不同的方法

  1. 函数

test03=# create or replace function f_upsert(int,text,timestamp) returns void as $$ declare res int; begin update test set info=$2,crt_time=$3 where id=$1; if not found then insert into test (id,info,crt_time) values ($1,$2,$3); end if; exception when others then return; end; $$ language plpgsql strict;
CREATE FUNCTION

test03=# select f_upsert(1,'digoal',now()::timestamp);

f_upsert

(1 row)

test03=# select * from test;
id | info | crt_time
----+--------+----------------------------
2 | pu | 2017-04-24 15:28:20.37392
1 | digoal | 2017-04-24 15:31:29.254325
(2 rows)

test03=# select f_upsert(1,'digoal001',now()::timestamp);

f_upsert

(1 row)

test03=# select * from test;
id | info | crt_time
----+-----------+---------------------------
2 | pu | 2017-04-24 15:28:20.37392
1 | digoal001 | 2017-04-24 15:31:38.0529
(2 rows)

test03=# select f_upsert(3,'hello',now()::timestamp);

f_upsert

(1 row)

test03=# select * from test;
id | info | crt_time
----+-----------+---------------------------
2 | pu | 2017-04-24 15:28:20.37392
1 | digoal001 | 2017-04-24 15:31:38.0529
3 | hello | 2017-04-24 15:31:49.14291
(3 rows)

  1. WITH语法,用法1

create table test(id int primary key, info text, crt_time timestamp);
存在则更新,不存在则插入。

with upsert as (update test set info=$info,crt_time=$crt_time where id=$id returning *) insert into test select $id,$info,$crt_time where not exists (select 1 from upsert where id=$id);
替换变量,进行测试

with upsert as (update test set info='test',crt_time=now() where id=1 returning *) insert into test select 1,'test',now() where not exists (select 1 from upsert where id=1);
同时插入一条不存在的值,只有一个会话成功,另一个会话会报PK约束错误。

  1. WITH语法,用法2

即使表没有PK或者唯一约束,也能保证并发。

create table test(id int, info text, crt_time timestamp);
3.1 对于记录不存在,可以保证只有一个session插入数据,对于同一条数据更新,先来的session会lock着记录,后来的session会wait。

with
w1 as(select ('x'||substr(md5('$id'),1,16))::bit(64)::bigint as tra_id),
upsert as (update test set info=$info,crt_time=$crt_time where id=$id returning *)
insert into test select $id, $info, $crt_time from w1
where pg_try_advisory_xact_lock(tra_id) and not exists (select 1 from upsert where id=$id);
替换变量,进行测试

with
w1 as(select ('x'||substr(md5('1'),1,16))::bit(64)::bigint as tra_id),
upsert as (update test set info='digoal0123',crt_time=now() where id=1 returning *)
insert into test select 1, 'digoal0123', now() from w1
where pg_try_advisory_xact_lock(tra_id) and not exists (select 1 from upsert where id=1);

INSERT 0 0

test03=# select * from test;
id | info | crt_time
----+------------+---------------------------
2 | pu | 2017-04-24 15:28:20.37392
3 | hello | 2017-04-24 15:31:49.14291
1 | digoal0123 | 2017-04-24 15:31:38.0529
(3 rows)

with
w1 as(select ('x'||substr(md5('4'),1,16))::bit(64)::bigint as tra_id),
upsert as (update test set info='digoal0123',crt_time=now() where id=4 returning *)
insert into test select 4, 'digoal0123', now() from w1
where pg_try_advisory_xact_lock(tra_id) and not exists (select 1 from upsert where id=4);

INSERT 0 1

test03=# select * from test;
id | info | crt_time
----+------------+----------------------------
2 | pu | 2017-04-24 15:28:20.37392
3 | hello | 2017-04-24 15:31:49.14291
1 | digoal0123 | 2017-04-24 15:31:38.0529
4 | digoal0123 | 2017-04-24 15:38:39.801908
(4 rows)
3.2 对于记录不存在,可以保证只有一个session插入数据,对于同一条数据更新,先来的session会更新数据,后来的session不等待,直接失败。

with w1 as(select ('x'||substr(md5('$id'),1,16))::bit(64)::bigint as tra_id),
upsert as (update test set info=$info,crt_time=$crt_time from w1 where pg_try_advisory_xact_lock(tra_id) and id=$id returning *)
insert into test select $id,$info,$crt_time from w1
where pg_try_advisory_xact_lock(tra_id) and not exists (select 1 from upsert where id=$id);
替换变量,进行测试

with w1 as(select ('x'||substr(md5('1'),1,16))::bit(64)::bigint as tra_id),
upsert as (update test set info='test',crt_time=now() from w1 where pg_try_advisory_xact_lock(tra_id) and id=1 returning *)
insert into test select 1,'test',now() from w1
where pg_try_advisory_xact_lock(tra_id) and not exists (select 1 from upsert where id=1);

INSERT 0 0

test03=# select * from test;
id | info | crt_time
----+------------+----------------------------
2 | pu | 2017-04-24 15:28:20.37392
3 | hello | 2017-04-24 15:31:49.14291
4 | digoal0123 | 2017-04-24 15:42:50.912887
1 | test | 2017-04-24 15:44:44.245167
(4 rows)

https://github.com/bkahers/rvfnvr
https://github.com/boststro/hfesgh
https://github.com/biglein/uplwoi
https://github.com/vsrulov/nuzlhc
https://github.com/nahuanghan/ylqgry
https://github.com/iclitealph/iiypma
https://github.com/bell42surf/cigxme
https://github.com/milespopp1/nwsvju
https://github.com/estemper/wlwemq
https://github.com/cuperc-ei/hucmdz
https://github.com/adaloleto/jvlwei
https://github.com/vtufek/ixojlk
https://github.com/elkuf/zbmlmu
https://github.com/rybehoqije/qpxcuy
https://github.com/johnspeim/qvccig
https://github.com/earthedged/xejdei
https://github.com/raptiguy/yvvpzz
https://github.com/mikehadel/kbcjzg
https://github.com/yasaihao/wbrudv
https://github.com/sun43liver/kdigjy
https://github.com/circlefiro/emjqtb
https://github.com/drawertria/lelpbd
https://github.com/milo-zz/cmiejc
https://github.com/phejaat/kvurkr
https://github.com/admoney248/bsscoo
https://github.com/brendakind/shkjfc
https://github.com/flexi92/znvhlw
https://github.com/wvib/rkodjc
https://github.com/meatmenu46/gbmjzc
https://github.com/mgraphie/iabryc
https://github.com/zeaverxxx/lmzxpk
https://github.com/lextrax/vikqzz
https://github.com/taylordavi/psktxm
https://github.com/ophiltus/eagkox
https://github.com/ashleybenj/kuwhsk
https://github.com/itajarov-z/yoakhm
https://github.com/mrongcorki/eoawpf
https://github.com/kvarmund/mqsyak
https://github.com/mfeeldi/pkldfj
https://github.com/mstanilla/kojqgy
https://github.com/expensol/wfoyxr
https://github.com/ammarkilhe/ayfkcm
https://github.com/rgoner/ypuqza
https://github.com/djchowe/fdxlkd
https://github.com/testhead41/odubnz
https://github.com/jsdevine03/uwrika
https://github.com/phini53/rubpol
https://github.com/jeyjon2000/uhbnka
https://github.com/wilfierliu/wkmvfh
https://github.com/sdfbbfasbd/pwazpa
https://github.com/yahou093/spvezx
https://github.com/adanargrit/odchni
https://github.com/danielbuer/jsimnt
https://github.com/skatecase/dizkej
https://github.com/debramorga/vitmta
https://github.com/simonphill/kfvtdp
https://github.com/marineello/ltphdo
https://github.com/zpentest/speprl
https://github.com/frocaon/mjlycw
https://github.com/dweisingto/ermbis
https://github.com/calhoudy/inqygy
https://github.com/annamice99/xggrcc
https://github.com/komunour/bwwteo
https://github.com/voidhaw/shysll
https://github.com/zavakhar/rlfttm
https://github.com/daimonaka/ofmphu
https://github.com/rosa997/sebzdj
https://github.com/fzandrew/lfqtpb
https://github.com/siqijumofe/prjagc
https://github.com/lxglygong/aevztn
https://github.com/dancer23gr/madoat
https://github.com/lmc3330a/pelgen
https://github.com/lovelydown/lgetwq
https://github.com/hasenog/cjpuey
https://github.com/moseswedde/zwwwpt
https://github.com/unit3room/kansmd
https://github.com/shammeha90/fzwyqm
https://github.com/marit1993/riacra
https://github.com/naoliker23/lxngky
https://github.com/evrrim/fcqwlz
https://github.com/escbm/cijphr
https://github.com/milmeion/mxvhpt
https://github.com/dillardw/tyazbl
https://github.com/westzykaz2/anezru
https://github.com/jacklobs10/srskni
https://github.com/romciti08/cyrcxy
https://github.com/appstory09/fxzkud
https://github.com/spoon3deat/zzevnz
https://github.com/anithejs/epvhln
https://github.com/amikshah/puvqhl
https://github.com/josiancogh/bzqdam
https://github.com/gabris-d/yfaktf
https://github.com/brassrepai/ntlpbi
https://github.com/mcbossy/gvglxj

相关文章
|
9天前
|
缓存 测试技术 API
Qwen 3.7 Plus 与 Max 实测:性价比与多模态能力差异解析(2026)
2026 年 6 月 1 日,阿里悄无声息地发布了 Qwen 3.7 Plus,距 Qwen 3.7 Max 上线刚好 11 天。同样的 1M 上下文,同样的 35 小时自治上限。但价格才是头条:Plus 是 0.40/M输入,Max是 2.50/M——便宜约 6 倍——并且还能看图、看视频。Vision Arena 上 Plus 已经排到 #16。所以这周真正值得讨论的问题不是”要不要为视觉能力买单”,而是”Max 凭什么用 6 倍价格换来 2 个百分点的 benchmark 领先”。
|
10天前
|
JavaScript 定位技术 API
CodeGraph 爆火:编程 Agent 需要的不是更多上下文,而是一张提前画好的代码地图
CodeGraph 是一款爆火的本地代码智能工具,通过 tree-sitter 解析 AST 构建结构化知识图谱(存于 SQLite),为编程 Agent 提前生成“代码地图”。它显著降低 Agent 在中大型项目中的探索成本——实测工具调用减少71%、Token 降57%、速度提升46%,支持19+语言及主流框架路由识别,完全离线、无需 API Key。
776 11
CodeGraph 爆火:编程 Agent 需要的不是更多上下文,而是一张提前画好的代码地图
|
10天前
|
人工智能 运维 JavaScript
阿里云Qoder CN(原通义灵码)全解析 产品形态、版本划分与技术适配说明
在AI辅助开发与智能办公工具持续普及的当下,阿里云旗下原通义灵码正式更名为Qoder CN,同时延伸出QoderWork CN、Qoder CN CLI、Qoder CN Mobile等多款配套产品,形成覆盖代码开发、日常办公、终端交互、移动端使用的完整工具矩阵。Qoder CN核心定位为AI智能编码助手,深度适配主流代码编辑器、集成开发环境以及终端场景;QoderWork CN则偏向桌面端综合办公辅助,二者面向不同使用场景,划分了多个版本档位,搭配差异化资源配额、功能权限与计费规则,同时兼容多款主流大模型。
804 7
|
10天前
|
存储 安全 Java
AgentScope Java 2.0:打造分布式、企业级智能体底座
AgentScope 2.0 面向分布式部署、稳定运行、权限安全等企业级需求全面升级,打造支持多租户隔离与长期稳定运行的企业级智能体底座。
|
10天前
|
JSON 缓存 安全
通过 CC Switch 本地路由让 Codex CLI 接入 DeepSeek 等第三方模型
CC Switch 通过本地路由(`127.0.0.1:15721`)实现协议转换:将 Codex 的 Responses API 请求自动映射为 DeepSeek 等厂商的 Chat Completions 接口,兼容流式响应与工具调用,无需修改 Codex 源码,安全隔离 API Key。(239字)
2122 4
通过 CC Switch 本地路由让 Codex CLI 接入 DeepSeek 等第三方模型
|
10天前
|
人工智能 弹性计算 安全
阿里云618活动时间、活动入口、优惠活动详细解读
2026年阿里云618创新加速季已全面开启,作为年度力度最大的云产品促销活动,本次大促覆盖轻量应用服务器、ECS云服务器、GPU云服务器、数据库、AI算力、安全服务、CDN等全品类产品,推出5亿元算力补贴、新用户限时秒杀、普惠满减、企业专享、免费试用、云大使返佣等多重福利,个人开发者、中小企业、AI团队均可享受专属低价。本文将系统梳理2026年阿里云618活动的完整时间节点、官方参与入口、各类优惠细则、使用规则、热门产品推荐及实操代码,帮助用户精准参与、高效省钱,以最低成本完成上云部署。
1828 6
|
10天前
|
数据采集 人工智能 前端开发
让 Coding Agent 从黑盒到透明:阿里云 Agent 观测审计数据采集实践
AI Agent 规模化落地带来执行黑盒、行为难追溯、成本难度量三大难题。阿里云基于 OTel 标准,面向 Coding Agent、个人通用助理和框架型 Agent,推出 LoongSuite Pilot、插件及探针等无侵入采集方案,让 Agent 实现可看见、可分析、可审计、可治理。
772 152
|
10天前
|
人工智能 运维 自然语言处理
阿里云百炼Qwen3.7-Max模型详解:综合能力、核心优势与订阅计划参考指南
2026年,大模型技术持续向通用化、高性能、场景化方向迭代,阿里云百炼作为一站式大模型服务平台,持续推出迭代升级的模型产品,Qwen3.7-Max便是当前主力旗舰级大模型之一。该模型依托深度优化的底层架构与大规模训练数据,在文本理解、逻辑推理、多模态交互、代码生成、长文本处理等多个维度实现能力升级,同时搭配灵活的订阅计划体系,能够适配个人开发者、中小企业、大型企业、政企机构等不同类型用户的使用需求。
624 2