Postgresql insert on conflict笔记

Posted Jruing

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Postgresql insert on conflict笔记相关的知识,希望对你有一定的参考价值。

描述

针对数据写入时有主键冲突的情况,INSERT ON CONFLICT语法可以将冲突主键的INSERT行为转换为UPDATE行为,从而实现冲突主键的覆盖写入。该特性又称UPSERT覆盖写,与MySQL的REPLACE INTO类似。

[ WITH [ RECURSIVE ] with_query [, ...] ]
INSERT INTO table_name [ AS alias ] [ ( column_name [, ...] ) ]
     DEFAULT VALUES | VALUES (  expression | DEFAULT  [, ...] ) [, ...] | query 
    [ ON CONFLICT [ conflict_target ] conflict_action ]
    [ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ]
其中,conflict_target为:
    (  index_column_name | ( index_expression )  [ COLLATE collation ] [ opclass ] [, ...] )
其中,conflict_action为:
    DO NOTHING
    DO UPDATE SET  column_name =  expression | DEFAULT  |
                    ( column_name [, ...] ) = (  expression | DEFAULT  [, ...] )
                   [, ...]
              [ WHERE condition ] 

ON CONFLICT子句可以实现覆盖写入。该子句由conflict_target和conflict_action组成。

参数 说明
conflict_target conflict_action取值为Do Update时,conflict_target需要指定用来定义冲突的主键列或唯一索引列。conflick_action取值为Do Nothing时,conflict_target可省略。
conflict_action 用于指定冲突后需要执行的动作。取值说明:DO NOTHING:如果conflict_target指定的列有冲突,则丢弃待插入的数据。DO UPDATE:如果conflict_target指定的列有冲突,则按照后面的UPDATE子句进行数据覆盖。

创建测试表

CREATE TABLE jruing.user_info (
    "name" varchar(255),
    "age" int4,
    "sex" varchar(255),
    "inserttime" date,
    constarint "user_info_pk" primary key ("name")
)

新增测试数据

insert into table_name(name, age, sex,inserttime) values(\'jruing\',\'男\',27,\'2023-05-10 00:00:00\') 

insert 新增时忽略已存在的数据

insert into table_name(name, age, sex,inserttime) values(\'jruing\',27,\'男\',\'2023-05-10 00:00:02\') on conflict(name) do nothing

insert 有则更新,无则插入

insert into table_name(name, age, sex, inserttime) values (\'jruing\',27,\'男\',\'2023-05-10 00:00:02\') on conflict(name) do update set inserttime=EXCLUDED.inserttime

注意事项

confilct中包含的字段必须为冲突的列名(冲突是指违反主键约束,唯一约束等其他约束)

如何在 PostgreSQL 9.5 中执行 INSERT INTO SELECT 和 ON DUPLICATE UPDATE?

【中文标题】如何在 PostgreSQL 9.5 中执行 INSERT INTO SELECT 和 ON DUPLICATE UPDATE?【英文标题】:How to do INSERT INTO SELECT and ON DUPLICATE UPDATE in PostgreSQL 9.5? 【发布时间】:2017-02-01 11:05:36 【问题描述】:

我正在尝试在 PostgreSQL 中执行以下操作

INSERT INTO blog_sums ( blog_id, date, total_comments)
    SELECT blog_id, '2016-09-22', count(comment_id) as total_comments_update
    FROM blog_comments
    WHERE date = '2016-09-22'
    GROUP BY blog_id         
ON CONFLICT (blog_id ,date)
DO UPDATE SET blog_sums.total_comments = total_comments_update;

我在 date + blog_id 上有唯一键,但我不断收到错误消息:

错误:列“total_cmets_update”不存在

我正在寻找在这种情况下更新重复/冲突的“正确”方式和最有效的方式

我的桌子是

blog_comments (blog_id, comment_id, comment, date)
blog_sums ( blog_id, date, total_comments) . unique on blog_id+date

谢谢

【问题讨论】:

【参考方案1】:

您不能从DO UPDATE SET 子句中的选择访问列别名。您可以使用 excluded 表别名,其中包括由于冲突而无法插入的所有行:

INSERT INTO blog_sums ( blog_id, date, total_comments)
    SELECT blog_id, '2016-09-22', count(comment_id) as total_comments_update
    FROM blog_comments
    WHERE date = '2016-09-22'
    GROUP BY blog_id         
ON CONFLICT (blog_id ,date)
DO UPDATE SET total_comments = excluded.total_comments;

所以最后一行中的excluded.total_comments 指的是我们尝试插入但由于冲突而无法插入的total_comments 的值。

【讨论】:

不要忘记 GROUP BY 否则你会得到(使用 postgresql 9.6.1):错误:ON CONFLICT DO UPDATE 命令不能再次影响行提示:确保没有建议插入的行在同一命令中具有重复的约束值。

以上是关于Postgresql insert on conflict笔记的主要内容,如果未能解决你的问题,请参考以下文章

Postgresql EXCLUDE 约束在 INSERT 时未触发 ON CONFLICT

如何在 flask_sqlalchemy 中使用 PostgreSQL 的“INSERT...ON CONFLICT”(UPSERT)功能?

如何将 DELETE 的返回值插入到 postgresql 中的 INSERT 中?

Postgresql 日志收集

postgresql----INSERT

mysql_insert_id 替代 postgresql