postgresql 9.5版本之前实现upsert功能

最近有开发人员问,有没有办法实现在pg9.5版本之前实现upsert功能,现整理如下

--创建测试表,注意此处先不要主键或唯一约束
create table t2 (id int,name varchar(100));

-- pg 在9.5之前实现不存在则插入
-- 现在需要实现,当id字段的值存在时,则更新name字段的值,如果id字段的值不存在,则执行插入
with upsert as (update t2 set name='rudy1' where id=5 returning *) insert into t2 select 5,'rudy' where not exists (select 1 from upsert where id=5);
--注意使用此种方法并不能保证两个事务同时插入一条数据

-- session1执行该语句,成功
postgres=# begin;
BEGIN
postgres=# with upsert as (update t2 set name='rudy2' where id=5 returning *) insert into t2 select 5,'rudy' where not exists (select 1 from upsert where id=5);
INSERT 0 1
-- session2执行该语句,也成功
postgres=# begin;
BEGIN
postgres=# with upsert as (update t2 set name='rudy2' where id=5 returning *) insert into t2 select 5,'rudy' where not exists (select 1 from upsert where id=5);
INSERT 0 1

--两者都提交后发现id=5的数据有两条
postgres=# select * from t2;
 id | name
----+------
  5 | rudy
  5 | rudy

--为了保证并发,此时可以给表加上主键或唯一键
  postgres=# alter table t2 add primary key(id);
ALTER TABLE

 --此时session2再提交语句则会报错
postgres=# begin;
BEGIN
postgres=# with upsert as (update t2 set name='rudy3' where id=5 returning *) insert into t2 select 5,'rudy' where not exists (select 1 from upsert where id=5);
ERROR:  duplicate key value violates unique constraint "t2_pkey"
DETAIL:  Key (id)=(5) already exists.

--那有没有办法实现在表上没有主键或唯一约束时,也能保证并发呢?

--有,此时需要使用pg_try_advisory_xact_lock(其是一个轻量级的锁,在事务回滚或提交后,会自动释放锁),但其接受的参数是整数,为了保证尽量唯一,可以使用md5函数

--借助于lock实现upsert,注意此sql对于记录不存在,可以保证只有一个session插入数据,对于同一条数据更新,先来的session会lock着记录,后来的session会wait
with w1 as(select ('x'||substr(md5('6'),1,16))::bit(64)::bigint as tra_id),
upsert as (update t2 set name='rudy2' where id=6 returning *)
insert into t2 select 6,'rudy'
from w1 where pg_try_advisory_xact_lock(tra_id) and not exists (select 1 from upsert where id=6);

--借助于lock实现upsert,注意此sql对于记录不存在,可以保证只有一个session插入数据,对于同一条数据更新,先来的session会更新数据,后来的session 失败
with w1 as(select ('x'||substr(md5('6'),1,16))::bit(64)::bigint as tra_id),
upsert as (update t2 set name='rudy2' from w1 where pg_try_advisory_xact_lock(tra_id) and id=6 returning *)
insert into t2 select 6,'rudy'
from w1 where pg_try_advisory_xact_lock(tra_id) and not exists (select 1 from upsert where id=6); 

--后记
--为了保证性能,id字段最好有索引(但不一定是主键或唯一约束时)
--如果校验字段是否字段不为id,把相应字段的替换掉id字段则可
--由md5虚拟的tra_id并不保证一定是唯一的,但重复的概率极低

-- 在pg9.5中可以直接使用upsert,注意此时要求表上有主键或唯一约束
insert into t2 values(5,'rudy1') ON CONFLICT(id) do update set name=EXCLUDED.name ;

--对于mysql可以使用insert into on duplicate key实现类似功能(其也要求有主键或唯一约束)在此不详细举例
--对于oracle可以使用merge into,想想还是这个更强大,嘿嘿
  
时间: 2024-11-03 17:34:44

postgresql 9.5版本之前实现upsert功能的相关文章

来往4.1版本的公众账号功能已经完整上线

摘要: 来往今日发布4.1版本:iOS涂鸦功能上线 10月25日上午消息,阿里巴巴旗下好友互动产品来往今天发布4.1版本,目前已经在 苹果 App Store上线.4.1版本上线了此前安卓版本中颇受欢迎的涂鸦 来往今日发布4.1版本:iOS涂鸦功能上线 10月25日上午消息,阿里巴巴旗下好友互动产品来往今天发布4.1版本,目前已经在苹果App Store上线.4.1版本上线了此前安卓版本中颇受欢迎的涂鸦功能. 来往的涂鸦功能既支持创作涂鸦,也可以在照片上涂鸦,目前有8种画笔尺寸和十几种颜色可选.

陌陌今日透露将在即将发布的5.0版本中引入星级功能

摘要: 陌陌首推用户星级机制 净化会员体系 月10日下午消息,陌陌今日透露将在即将发布的5.0版本中引入星级功能,将用户划分为不可信用户.一星到五星6个等级,引入用户信用体系,过滤 陌陌首推用户星级机制 净化会员体系 月10日下午消息,陌陌今日透露将在即将发布的5.0版本中引入"星级功能",将用户划分为不可信用户.一星到五星6个等级,引入用户信用体系,过滤垃圾信息骚扰. "很多人在使用社交应用过程中都曾被目的不纯的人或垃圾信息骚扰."陌陌科技COO王力表示,陌陌将在

来往今日发布4.1版本:iOS涂鸦功能上线

摘要: 来往今日发布4.1版本:iOS涂鸦功能上线 10月25日上午消息,阿里巴巴旗下好友互动产品来往今天发布4.1版本,目前已经在 苹果 App Store上线.4.1版本上线了此前安卓版本中颇受欢迎的涂鸦  来往今日发布4.1版本:iOS涂鸦功能上线 10月25日上午消息,阿里巴巴旗下好友互动产品来往今天发布4.1版本,目前已经在苹果App Store上线.4.1版本上线了此前安卓版本中颇受欢迎的涂鸦功能. 来往的涂鸦功能既支持创作涂鸦,也可以在照片上涂鸦,目前有8种画笔尺寸和十几种颜色可选

PostgreSQL upsert功能(insert on conflict do)的用法

标签 PostgreSQL , upsert , insert on conflict do 背景 PostgreSQL 9.5 引入了一项新功能,UPSERT(insert on conflict do),当插入遇到约束错误时,直接返回,或者改为执行UPDATE. 语法如下 Command: INSERT Description: create new rows in a table Syntax: [ WITH [ RECURSIVE ] with_query [, ...] ] INSER

飞信PC客户端V5.4.0版本增加飞信电话功能

飞信PC客户端V5.4.0版本已于2014年4月22日在飞信官网正式发布.飞信2014和沟通版(V 5.4.0)为基于全新构架开发的版本,性能更加稳定,更适应目前互联网的前沿技术发展趋势.该版本主要宣传功能为"视觉更新"."屏幕分享"."个人资料"."身边"和"公众好友". 版本简述: 飞信2014和沟通版(V 5.4.0)为基于全新构架开发的版本,性能更加稳定,更适应目前互联网的前沿技术发展趋势.该版本主

Oracle和PostgreSQL的最新版本性能PK

来自PostgreSQL中国社区发起人之一,阿里数据库内核高级技术专家德歌的分享.使用BenchmarkSQL测试Oracle 12c的TPC-C性能,并在同样的硬件测试环境下,测试了PostgreSQL 9.5.0.相关数据对比如下. 测试机: 3 * PCI-E SSD,逻辑卷条带,XFS,数据块对齐,16核开HT,256G内存. benchmarkSQL 配置请参考: http://blog.163.com/digoal@126/blog/static/163877040201511234

ThinkPHP v3.1.2版本模板继承的功能说明

模板继承是3.1.2版本添加的一项更加灵活的模板布局方式,模板继承不同于模板布局,甚至来说,应该在模板布局的上层.模板继承其实并不难理解,就好比类的继承一样,模板也可以定义一个基础模板(或者是布局),并且其中定义相关的区块(block),然后继承(extend)该基础模板的子模板中就可以对基础模板中定义的区块进行重载. 因此,模板继承的优势其实是设计基础模板中的区块(block)和子模板中替换这些区块. 每个区块由<block></block>标签组成,并且不支持block标签的嵌

Ubuntu发12.10版本增加远程登录功能

新浪科技讯 10月22日晚间消息,开源操作系统Ubuntu于日前上线了最新的桌面版12.10版本,其主要特点融合了桌面和远程的体验,向Web应用的整合更近了一步.Ubuntu 12.10代号Quantal Quetzal,采用 Linux内核3.5,运行GNOME 3.6桌面.这也是Ubuntu首次ISO镜像的大小超过800Mb,这意味着一张CD无法刻入整个系统,Ubuntu CD成为历史.新版Ubuntu首次原生支持Web应用,增加了远程登录.Amazon搜索等功能.其中,Ubuntu将开始从

解密ThinkPHP3.1.2版本之独立分组功能应用_php实例

ThinkPHP的分组功能是广为开发者使用的一个具有很大实用价值的功能,该功能可以解决中大型项目情况中MVC分层文件过多导致不易管理的问题. 而ThinkPHP3.1.2版本添加的独立分组功能则为此类问题提出了新的解决思路,更加适合组件化的开发模式.我们就此了解下这一功能. 1.概述 独立分组功能不影响原有分组模式的运行,并且原有分组模式仅需移动目录结构即可完成独立分组模式的升级,无需任何应用代码的改动. 而且新的独立分组可以很方便的独立装卸和移动,可以摆脱原来普通分组文件分散在各个不同的目录下