PostgreSQL的upsert实例操作(insert on conflict do)

建表语句:

DROP TABLE IF EXISTS "goods";
CREATE TABLE "goods" (
 "store_cd" int4 NOT NULL,
 "good_cd" varchar(50) COLLATE "pg_catalog"."default" NOT NULL,
 "name" varchar(255) COLLATE "pg_catalog"."default"
);

INSERT INTO "goods" VALUES (101, '1', '张三');
INSERT INTO "goods" VALUES (102, '2', '李四');
INSERT INTO "goods" VALUES (103, '3', '王五');

ALTER TABLE "goods" ADD CONSTRAINT "pr_cd_key" PRIMARY KEY ("store_cd", "good_cd");

表数据:

数据存在则更新数据,不存在则插入数据

INSERT INTO GOODS VALUES ( 104, '4', '赵六' )
ON CONFLICT ON CONSTRAINT pr_key_cd DO
UPDATE
 SET NAME = '更新'
WHERE
 GOODS.STORE_CD = '104'
 AND GOODS.GOOD_CD = '4'

pr_key_cd为必须为唯一主键,也可以用下面写法(注意:必须保证筛选出数据唯一)

INSERT INTO GOODS VALUES ( 104, '4', '赵六' )
ON CONFLICT ( STORE_CD, GOOD_CD ) DO
UPDATE
 SET NAME = '更新'
WHERE
 GOODS.STORE_CD = '104'
 AND GOODS.GOOD_CD = '4'

上面的两种的写法,是先执行insert如果主键冲突则执行update,没有冲突就执行insert了。要是想先执行update语句呢?

update更新失败执行insert,更新成功则执行update。

WITH TABLE1 AS ( UPDATE GOODS SET NAME = '更新' WHERE STORE_CD = '104' AND GOOD_CD = '4' RETURNING * )
INSERT INTO GOODS SELECT 104, '4', '赵六'
WHERE NOT EXISTS ( SELECT 1 FROM TABLE1 WHERE STORE_CD = '104' AND GOOD_CD = '4' )

补充:Postgresql插入或更新操作upsert

幂等性的一个要求是多次操作的结果一致。对于update操作,多次直接的结果都是最后update的值,是满足需求的。但对于insert,如果已经插入,第二次会报错,duplicate error, 主键重复或者unique key duplicate。所以需要做一下处理。

最简单的就是,try-catch,当报错的时候,调用update去更新,或者策略更简单点,直接返回就行,不需要更新,以第一条为准。

PostgreSQL从9.5之后就提供了原子的upsert语法: 不存在则插入,发生冲突可以update。

Inert语法

官方文档: https://www.postgresql.org/docs/devel/sql-insert.html

[ WITH [ RECURSIVE ] with_query [, ...] ]
INSERT INTO table_name [ AS alias ] [ ( column_name [, ...] ) ]
  [ OVERRIDING { SYSTEM | USER} VALUE ]
  { 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 [, ...] ) = [ ROW ] ( { expression | DEFAULT } [, ...] ) |
          ( column_name [, ...] ) = ( sub-SELECT )
         } [, ...]
       [ WHERE condition ]

index_column_name

The name of a table_name column. Used to infer arbiter indexes. Follows CREATE INDEX format. SELECT privilege on index_column_name is required.

index_expression

Similar to index_column_name, but used to infer expressions on table_name columns appearing within index definitions (not simple columns). Follows CREATE INDEX format. SELECT privilege on any column appearing within index_expression is required.

使用示例

创建表

CREATE TABLE "test"."upsert_test" (
 "id" int4 NOT NULL,
 "name" varchar(255) COLLATE "pg_catalog"."default"
)
;

当主键id冲突时,更新其他字段

INSERT INTO test.upsert_test(id, "name")
  VALUES(1, 'm'),(2, 'n'),(4, 'c')
  ON conflict(id) DO UPDATE
  SET "name" = excluded.name;

did 冲突的主键

EXCLUDED 代指要插入的记录

当主键或者unique key发生冲突时,什么都不做

INSERT INTO test.upsert_test(id, "name")
VALUES(1, 'm'),(2, 'n'),(4, 'c')
ON conflict(id) DO NOTHING;

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。如有错误或未考虑完全的地方,望不吝赐教。

(0)

相关推荐

  • PostgreSQL 序列增删改案例

    创建序列 CREATE SEQUENCE if not exists test_mergetable_id_seq INCREMENT 1 MINVALUE 1 MAXVALUE 999999999 START 1 CACHE 1; //或者: create sequence if not exists test_mergetable_id_seq increment by 1 minvalue 1 no maxvalue start with 1; 指定序列(给表的主键指定创建好的序列) al

  • postgreSQL的crud操作详解

    postgreSQL学习笔记 欢迎大家指出问题! 版本从6.0开始支持SQL解释器 安装一路下一步. 1.创建数据库 ​ //命令行操作 ​ createdb database_name; ​ CREATE DATABASE database_name; psql -l //展示所有数据库 psql database_name //进入数据库 2.删除数据库 ​ dropdb database; ​ DROP DATABASE database_name; 3.创建表 ​ create tabl

  • PostgreSQL 默认权限查看方式

    如何查看PostgreSQL默认权限 当我们对Postgresql的某个用户授予默认权限时, pg_default_acl表存储要被分配给新创建对象的初始权限.你可能通过查询该表获取默认权限,先了解下官方文档的解释: 表 50-17. pg_default_acl的列: 名称 类型 引用 描述 oid oid 行标识符(隐藏属性,必须被显式选择才会显示) defaclrole oid pg_authid.oid 与此项相关的角色的OID defaclnamespace oid pg_namesp

  • PostgreSQL批量修改函数拥有者的操作

    Postgresql如何批量修改函数拥有者,默认创建的函数对象的拥有者为当前创建的用户,如果使用postgres超级管理员创建一个test()的函数,拥有者就是postgres用户.下面讲解下如何批量修改拥有者. 本文演示的Postgresql版本如下: PostgreSQL 9.6.8 相关视图 要查询Postgresql的函数和函数参数需要使用函数视图和参数视图,分别记录了函数信息和参数列表信息. 视图一: information_schema.routines 视图routines包含当前

  • postgresql 赋权语句 grant的正确使用说明

    grant select on all tables in schema public to username; 此句是有效的复制语句 PG中有schema的概念, 以下的语句就是不行 网上得来终觉浅,错误比较多,还是要自己试试才行. 补充:postgresql关于访问视图需要的权限 某个用户访问一个视图,这个用户需要具备这个视图的schema的usage和这个视图本身的select权限,如果视图的基表来自其他schema,可能还需要其他schema的usage权限(根据postgresql改造

  • PostgreSQL 字符串拆分与合并案例

    我就废话不多说了,大家还是直接看代码吧~ with person_name as ( select c.id, array_to_string(array_agg(distinct p.c_name), ' , ') as p_name from biz_notification_config c join biz_notification_person p on p.id = any (string_to_array(c.persons, ',')::int[]) group by c.id

  • postgresql合并string_agg函数的实例

    1 有时候我们会需要将多条数据根据一些特别的字段做一些合并.比如下面这个查询,正常会查询出3条数据,但是我们会希望根据create_by 分成两列显示 2 这时候需要用到string_agg函数,先通过group by分组,在进行合并,当然查询结果需要满足group by的限制:sql语句: select create_by,string_agg(videoname,',') as videonames from w008_video_addr_info where id in (4248,53

  • postgresql重置序列起始值的操作

    我就废话不多说了,大家还是直接看代码吧~ -- 序列重置到1000 alter sequence sequence_name restart with 1000 -- 验证 SELECT nextval('sequence_name'); 补充:postgresql重置序列和自增主键 1. 问题背景 数据表中插入了几条测试数据,后又手动删除,导致后面插入数据的时候报主键冲突: ERROR: duplicate key value violates unique constraint "table

  • PostgreSQL的upsert实例操作(insert on conflict do)

    建表语句: DROP TABLE IF EXISTS "goods"; CREATE TABLE "goods" ( "store_cd" int4 NOT NULL, "good_cd" varchar(50) COLLATE "pg_catalog"."default" NOT NULL, "name" varchar(255) COLLATE "pg_

  • MSSQL 基本语法及实例操作语句

    MS SQL基本语法及实例操作 一:建表并初始化 ============================ create database mf2011 --创建数据库 use mf2011 --使用数据库 create table dept --创建"部门"表 ( www.jb51.net deptno int primary key, --部门编号(主键) dname nvarchar(30), --部门名称 loc nvarchar(30) --部门所在的地点 ) ----- c

  • layui监听工具栏的实例(操作列表按钮)

    废话不多说,直接上代码吧! <table id="demo" lay-filter="test"></table> <script type="text/html" id="barDemo"> <a class="layui-btn layui-btn-xs" lay-event="edit">查看详情</a> </scr

  • python接入支付宝的实例操作

    Python接入支付宝流程: 第一步: 首先要下载一个python的sdk,这个sdk在支付宝的开发者文档中是没有的,但是强大的python程序员自己开发了一套属于python的支付宝支付sdk. 下载方式:pip install python-alipay-sdk ,github的链接为 https://github.com/fzlee/alipay 第二步: 下载好sdk之后,需要对支付宝进行一些相关的配置,支付宝的环境分为两种,一为正式环境,也就是程序上线之后的环境. 二为沙箱环境,即开发

  • python3跳出一个循环的实例操作

    python跳出循环有两个关键字 1.continue跳过当前循环,进入下一次循环 for i in range(5):     if i == 3:         continue     print(i, end='\t') 结果是: 0       1       2       4 2.利用break关键字跳出整个循环 for i in range(5):     if i == 3:         break     print(i, end='\t') 结果是: 0       

  • java迭代器中删除元素的实例操作详解

    我们知道通过Iterator,可以对集合中的元素进行遍历.那么在其中遇到我们不需要的元素时,可不可以在遍历的时候顺便给删除呢?答案是当然可以.在Iterator下有一个remove函数,专门用于删除的操作.下面我们就remove进行讲解,然后对删除元素方法进行说明,最后带来实例的展示. 1.Iterator中的remove void remove():删除迭代器刚越过的元素 从基础集合中移除这个迭代器返回的最后一个元素(可选操作).两个线程中都删除,保证线程的同步. 2.删除元素说明 (1)迭代

  • python在协程中增加任务实例操作

    1.添加一个任务 task2 = visit_url('http://another.com', 3) asynicio.run(task2) 2.这 2 个程序一共消耗 5s 左右的时间.并没有发挥并发编程的优势 import asyncio import time async def visit_url(url, response_time): """访问 url""" await asyncio.sleep(response_time) r

  • python定义具名元组实例操作

    1.定义具名元组需要2个参数,第1个参数是类名,第2个参数是字段名,既可以是可迭代对象(如列表和元组),也可以是空格间隔的字符串: Card = collections.namedtuple("Card", ("rank", "suit")) Card = collections.namedtuple("Card", "rank suit") 2.初始化时以一串参数形式传入构造函数: card_test =

  • Java构建JDBC应用程序的实例操作

    我们在学习接口的时候.能够在里面做一些方法的调用.不过今天所要讲的JDBC,虽然也是连接数据库的一种接口,不过与类接口有着很大的区别,大家要注意区分.下面我们就构建JDBC的步骤进行了整理,还不会此类操作的小伙伴,一起来看看具体的内容吧. 1.加载数据库驱动. 通常使用 Class 类的 forName()静态方法来加载驱动. 例如如下代码: // 加载驱动 Class.forName(driverClass) 2.通过 DriverManager 获取数据库连接. DriverManager

  • MSSQL基本语法及实例操作语句

    刷新本地缓存 Ctrl+Shift+R 查询 select *from [table] 修改 1.普通更新 UPDATE [table] set [字段]=[values] 2.关联表更新 UPDATE A SET A1 = B1, A2 = B2, A3 = B3 FROM A, B WHERE A.ID = B.ID 删除(数据) delete [table] 删除(表) drop [table] 条件查询 select *from [table] where [字段]=[values] 事

随机推荐