数据存在则更新(UPSET 特性)

一、业务场景

某客户上线一段时间后,日志中出现大量主键冲突的日志,并且出现数据库繁忙。
ERROR: duplicate key value violates unique constraint “visit_workrecord_pkey”
Detail: Key (recordid)=(1105661718883) already exists.

问题: 此类日志会大量出现。
二、UPSET 场景演示

如果出现这种约束冲突后,该如何处理,在PostgreSQL中UPSET特性是指INSERT ... ON CONFLICT UPDATE,专门用来处理这种数据冲突的情况。

--  自定义一张用户登录日志表
CREATE TABLE  user_logins (
    user_name VARCHAR(200) PRIMARY KEY,
    login_cnt INT4,
    last_login_time TIMESTAMP(0) WITHOUT TIME ZONE
);

插入重复数据后报错

INSERT INTO user_logins     (user_name,login_cnt) VALUES
('frances',1),('mate',2),('frances',1);


2.1 冲突时更新

-- 先插入一条
INSERT INTO user_logins     (user_name,login_cnt) VALUES
('frances',1);

-- 重复插入
INSERT INTO user_logins     (user_name,login_cnt) VALUES
('mate',2),('frances',1)
ON conflict(user_name)
DO UPDATE SET
login_cnt = user_logins.login_cnt + EXCLUDED.login_cnt,last_login_time = now();

    ON CONFLICT() 定义冲突
    DO UPDATE SET 冲突动作
    内置表 EXCLUDED

批量操作,将三条数据批量操作时,会报错
在这里插入图片描述

在SQL标准中,sql merge也有同样的问题,因为一次请求中对行的处理,顺序是不固定的。数据库不知道应该以哪条为最后需要保留的

    标签 PostgreSQL , insert into on conflict , merge insert 背景 使用insert into on conflict 合并插入,如果一条SQL语句中,对一个KEY(冲突键,或冲突约束)多次发生冲突时,会报错。

2.2 冲突时不做任何操作

在发生冲突的时候不做任何处理。

select * from user_logins

-- TRUNCATE TABLE user_logins;
-- INSERT INTO user_logins     (user_name,login_cnt) VALUES  ('frances',1);
INSERT INTO user_logins     (user_name,login_cnt) VALUES
('mate',2),('frances',1)
ON conflict(user_name)
DO NOTHING ;

三、如果不存在则插入,存在则更新

需要有一个唯一键


3.1 MySQL 版本

MySQL语法支持如果数据存在则更新,不存在则插入,首先判断数据存在还是不存在的那个字段要设置成unique索引。

SELECT * FROM user_logins;
CREATE TABLE  user_logins (
    user_name VARCHAR(200) PRIMARY KEY,
    login_cnt INT4,
    last_login_time  date
);

-- 执行下面语句两次查看结果
INSERT INTO user_logins    (user_name,login_cnt,last_login_time) VALUES ('frances',3,now())
ON DUPLICATE KEY UPDATE login_cnt= 4,last_login_time= '2019-04-13';

3.2 PostgreSQL版本

SELECT * FROM user_logins;
CREATE TABLE  user_logins (
    user_name VARCHAR(200) PRIMARY KEY,
    login_cnt INT4,
    last_login_time  date
);
-- 执行两次看结果
INSERT INTO user_logins    (user_name,login_cnt,last_login_time) VALUES ('frances',3,now())
ON conflict(user_name)
DO UPDATE SET
login_cnt = 4,last_login_time = now();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值