PostgreSQL INSERT ON CONFLICT不存在则插入,存在则更新
近期有一个需求,向一张数据库表插入数据,如果是新数据则执行插入动作,如果插入的字段和已有字段重复,则更新该行对应的部分字段
1. 创建测试表
create table meta_data (
id serial,
user_id varchar(128) DEFAULT NULL,
file_name varchar(1024) DEFAULT NULL,
file_path varchar(1024) DEFAULT NULL,
update_time TIMESTAMP DEFAULT NULL,
UNIQUE (user_id,file_name)
); postgres=# \d meta_data
Table "public.meta_data"
Column | Type | Modifiers
-------------+-----------------------------+--------------------------------------------------------
id | integer | not null default nextval('meta_data_id_seq'::regclass)
user_id | character varying(128) | default NULL::character varying
file_name | character varying(1024) | default NULL::character varying
file_path | character varying(1024) | default NULL::character varying
update_time | timestamp without time zone |
Indexes:
"meta_data_user_id_file_name_key" UNIQUE CONSTRAINT, btree (user_id, file_name)
2. 插入两条测试数据
INSERT INTO meta_data (
user_id,
file_name,
file_path,
UPDATE_TIME )
VALUES ( 'user_id01',
'file_name01',
'/usr/local/file_name01',
now())
ON CONFLICT (user_id, file_name) DO UPDATE SET file_path = EXCLUDED.file_path, UPDATE_TIME = EXCLUDED.UPDATE_TIME; INSERT INTO meta_data (
user_id,
file_name,
file_path,
UPDATE_TIME )
VALUES ( 'user_id02',
'file_name02',
'/usr/local/file_name02',
now())
ON CONFLICT (user_id, file_name) DO UPDATE SET file_path = EXCLUDED.file_path, UPDATE_TIME = EXCLUDED.UPDATE_TIME;
postgres=# select * from meta_data;
id | user_id | file_name | file_path | update_time
----+-----------+-------------+------------------------+----------------------------
1 | user_id01 | file_name01 | /usr/local/file_name01 | 2019-09-23 17:14:52.39878
2 | user_id02 | file_name02 | /usr/local/file_name02 | 2019-09-23 17:14:53.118192
(2 rows)
3. 插入第三条测试数据,注意插入的字段user_id和file_name和第二条语句对应的字段是重复的
INSERT INTO meta_data (
user_id,
file_name,
file_path,
UPDATE_TIME )
VALUES ( 'user_id02',
'file_name02',
'/usr/local/file_name03',
now())
ON CONFLICT (user_id, file_name) DO UPDATE SET file_path = EXCLUDED.file_path, UPDATE_TIME = EXCLUDED.UPDATE_TIME;
postgres=# select * from meta_data;
id | user_id | file_name | file_path | update_time
----+-----------+-------------+------------------------+----------------------------
1 | user_id01 | file_name01 | /usr/local/file_name01 | 2019-09-23 17:14:52.39878
2 | user_id02 | file_name02 | /usr/local/file_name03 | 2019-09-23 17:16:52.457696
(2 rows)
可以看到新插入的第三条语句其实是更新了已存在的第二条记录
4.如何区分该条语句到底是执行了insert和update操作。
通过xmax字段的值是否为0,可以判断,如果是UPDATE,XMAX里面会填充更新事务号。注意直接用UPDATE语句更新的话,XMAX会写入0,因为是新版本,而老版本上XMAX会填入更新事务号。
我们重建表结构重新插入前面两条数据测试。
postgres=# select ctid,xmin,xmax,* from meta_data;
ctid | xmin | xmax | id | user_id | file_name | file_path | update_time
-------+------+------+----+-----------+-------------+------------------------+----------------------------
(0,1) | 3241 | 0 | 1 | user_id01 | file_name01 | /usr/local/file_name01 | 2019-09-23 17:31:27.360539
(0,2) | 3242 | 0 | 2 | user_id02 | file_name02 | /usr/local/file_name02 | 2019-09-23 17:31:28.10752
(2 rows)
再次插入第三条重复数据
INSERT INTO meta_data (
user_id,
file_name,
file_path,
UPDATE_TIME )
VALUES ( 'user_id02',
'file_name02',
'/usr/local/file_name03',
now())
ON CONFLICT (user_id, file_name) DO UPDATE SET file_path = EXCLUDED.file_path, UPDATE_TIME = EXCLUDED.UPDATE_TIME; postgres=# select ctid,xmin,xmax,* from meta_data;
ctid | xmin | xmax | id | user_id | file_name | file_path | update_time
-------+------+------+----+-----------+-------------+------------------------+----------------------------
(0,1) | 3241 | 0 | 1 | user_id01 | file_name01 | /usr/local/file_name01 | 2019-09-23 17:31:27.360539
(0,3) | 3243 | 3243 | 2 | user_id02 | file_name02 | /usr/local/file_name03 | 2019-09-23 17:33:53.459403
(2 rows)
ctid表示行号, xmin表示INSERT该记录的事务号,xmax表示删除该记录(update实际上是删除老版本新增新版本,所以老版本上xmax有值)的事务号。
手动执行update
postgres=# update meta_data set file_path='/usr/local/file_name02' where user_id='user_id02';
UPDATE 1
postgres=# select ctid,xmin,xmax,* from meta_data;
ctid | xmin | xmax | id | user_id | file_name | file_path | update_time
-------+------+------+----+-----------+-------------+------------------------+----------------------------
(0,1) | 3241 | 0 | 1 | user_id01 | file_name01 | /usr/local/file_name01 | 2019-09-23 17:31:27.360539
(0,4) | 3244 | 0 | 2 | user_id02 | file_name02 | /usr/local/file_name02 | 2019-09-23 17:33:53.459403
(2 rows)
结论
1、insert into on conflict do update,返回xmax等于0表示insert,不等于0表示update,
2、直接update,并提交,提交的记录上xmax为0。
PostgreSQL INSERT ON CONFLICT不存在则插入,存在则更新的更多相关文章
- PostgreSQL 务实应用(二/5)插入冲突
在项目中,有时会动态地按周期(如按月)封存统计数据,通常需要做这样的处理: 以按月封存为例,当月数据到达时,先需要检查该月是否有过记录,有则以更新的方式累加统计数字,无则添加一条记录. 假设我们创建以 ...
- oracle语句insert into select如何加后续插入条件
oracle语句insert into select如何加后续插入条件 2014-01-21 10:48匿名 分类:其他编程语言 | 浏览 2746 次 oracle中有批量插入语句insert i ...
- SQL语句的使用,SELECT - 从数据库表中获取数据 UPDATE - 更新数据库表中的数据 DELETE - 从数据库表中删除数据 INSERT INTO - 向数据库表中插入数据
SQL DML 和 DDL 可以把 SQL 分为两个部分:数据操作语言 (DML) 和 数据定义语言 (DDL). SQL (结构化查询语言)是用于执行查询的语法. 但是 SQL 语言也包含用于更新. ...
- spring data jpa开启批量插入、批量更新
spring data jpa开启批量插入.批量更新 原文链接:https://www.cnblogs.com/blog5277/p/10661096.html 原文作者:博客园--曲高终和寡 *** ...
- MySQL 避免重复数据的批量插入与批量更新
[转发] 导读 我们在向数据库里批量插入数据的时候,会遇到要将原有主键或者unique索引所在记录更新的情况,而如果没有主键或者unique索引冲突的时候,直接执行插入操作. 这种情况下,有三种方式执 ...
- MySql快速插入以及批量更新
MySql快速插入以及批量更新 插入: MySql提供了可以一次插入多条数据的用法: [sql] INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6), ...
- 在论坛中出现的比较难的sql问题:9(触发器专题 插入数据自动更新表数据)
原文:在论坛中出现的比较难的sql问题:9(触发器专题 插入数据自动更新表数据) 最近,在论坛中,遇到了不少比较难的sql问题,虽然自己都能解决,但发现过几天后,就记不起来了,也忘记解决的方法了. 所 ...
- mybatis+mysql批量插入和批量更新、存在及更新
mybatis+mysql批量插入和批量更新 一.批量插入 批量插入数据使用的sql语句是: insert into table (字段一,字段二,字段三) values(xx,xx,xx),(oo, ...
- oracle,uuid为主键,插入时直接更新id
uuid为主键,插入时自动更新 -- Create table create table TECHNOLOGYCOMPANY ( ID VARCHAR2(32) default SYS_GUID() ...
随机推荐
- sql 导入文件
zai SQLQuery4.sql 文件中 --BULK INSERT Table_1 from 'D:\aaaa#azzz.txt' with(fieldterminator=',',rowterm ...
- .net core 下载文件 其他格式
app.UseStaticFiles(); app.UseStaticFiles(new StaticFileOptions { //FileProvider = new PhysicalFilePr ...
- 计算机网络(三),TCP报文段详解
目录 1.TCP(Transmission Control Protocol传输控制协议)作用 2.TCP报文段详解 三.TCP报文段详解 1.TCP(Transmission Control Pro ...
- C语言 - 堆和栈
一.堆内存 1.就是程序员手动管理的一块内存,在C语言中,可以理解为用malloc.realloc等申请空间的一些函数,这些函数所申请的空间就是堆空间 2.C语言中,堆空间是申请和释放 malloc/ ...
- 4.JSP内置对象
JSP内置对象,JSP提供了由容器实现和管理的内置对象,也可以称之为隐含对象,这些内置对象不需要通过 JSP页面编写来实例化,在所有的JSP页面中都可以直接使用,它起到了简化页面的作用. 在JSP中一 ...
- R_Studio(决策树算法)鸢尾花卉数据集Iris是一类多重变量分析的数据集【精】
鸢尾花卉数据集Iris是一类多重变量分析的数据集 通过花萼长度,花萼宽度,花瓣长度,花瓣宽度4个属性预测鸢尾花卉属于(Setosa,Versicolour,Virginica)三个种类中的哪一类 针对 ...
- [CSP-S模拟测试]:城市游戏(图论+DP)
题目传送门(内部题109) 输入格式 第一行,两个整数$n,m$. 接下来$m$行,每行三个整数$u,v,l$,描述了一条道路连接的两个路口的编号以及道路的长度. 输出格式 输出一行一个整数,为所求的 ...
- Override和Overload的含义与区别
overload是重载,重载是一种参数多态机制,即代码通过参数的类型或个数不同而实现的多态机制. 是一种静态的绑定机制(在编译时已经知道具体执行的是哪个代码段). override是重写,重写是一种 ...
- html5 canvas简易时钟
<canvas id='clock' width=500 height=500> 您的浏览器需要升级 </canvas> <script type="text/ ...
- oracle存储过程及sql优化-(三)
接下来介绍上篇接触到的存储过程中的sql语句 insert into TMP_GT3_sbfgl_WJSTJB SELECT NSR.NSRSBH, NSR.NSRMC, NSR.SCJYDZ, ca ...