暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PostgreSQL的UPSERT在日志数据冲突中的应用

原创 梧桐 2023-08-17
284

概述

在日志数据的应用场景中,在事务中批量插入日志数据时,如果其中有一条数据违反表中的约束,整个插入事务就会回滚,PostgreSQL的UPSERT特性能解决这一问题。

我们通过例子来理解一下UPSERT:

首先定义一张用户登录日志表并插入一条数据

CREATE TABLE user_logins(user_name text primary key,login_cnt int4,last_login_time timestamp(0) without time zone); /*建表 user_logins*/ select * from user_logins /*看下结构 */ INSERT INTO user_logins(user_name, login_cnt) VALUES('steven',1); /*插入数据*/ select * from user_logins

user_logins表user_name字段定义了主键,这时,批量插入数据中如果有重复,会报错, 如下所示:

INSERT INTO user_logins(user_name,login_cnt) VALUES('mary',1),('steven',1); /*插入数据*/ DETAIL: Key (user_name)=(steven) already exists. /*报错*/

上面的SQL试图插入两条数据,mary这条数据不违反主键冲突,steven这条数据违反主键冲突,结果两条数据都不能插入。下面我们使用UPSERT处理冲突的数据,如当插入的数据冲突时不报错,同时更新冲突的数据,如下所示:

INSERT INTO user_logins(user_name, login_cnt) VALUES('mary',1),('steven',1) ON CONFLICT(user_name) DO UPDATE SET login_cnt=user_logins.login_cnt+EXCLUDED.login_cnt,last_login_time=now();

insert语句插入两条数据,并设置规则:当数据冲突时将登录次数字段login_cnt值加1, 同时更新最近登录时间last_login_time, ON CONFLICT(user_name)定义冲突类型为user_name字段,DO UPDATE SET是指冲突动作,后面定义了一个UPDATE语句。

上述SET命令中引用了user_loins表和内置表EXCLUDED, 引用原表user_loins访问表中己存在的冲突记录, 内置表EXCLUDED引用试图插入的值,再次查询表user_login, 例如:

SELECT * FROM user_logins; user_name | login_cnt | last_login_time -----------+-----------+--------------------- mary | 1 | steven | 2 | 2021-03-24 15:25:49 (2 rows)

一方面,我们发现steven这条冲突数据更新了login_cnt和last_login_time字段,而mary这条记录己正常插入。

也可以定义数据冲突后什么都不干,这时需指定DO NOTHING属性,例如:

INSERT INTO user_logins(user_name,login_cnt) VALUES('jack',1),('steven',1) ON CONFLICT(user_name) DO NOTHING;

再次查询表数据,新的数据jack这条己插入到表中,冲突的数据steven这行没变,结果如下:

SELECT * FROM user_logins; user_name | login_cnt | last_login_time -----------+-----------+--------------------- mary | 1 | steven | 2 | 2021-03-24 15:25:49 jack | 1 |
最后修改时间:2023-08-17 19:16:04
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论