PostgreSQL merge insert(insert into on conflict) ERRCODE_CARDINALITY_VIOLATION (Ensure that no rows proposed for insertion within the same command hav

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云原生数据库 PolarDB 分布式版,标准版 2核8GB
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介:

标签

PostgreSQL , insert into on conflict , merge insert


背景

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

原因:

                         * It is the user's responsibility to prevent this situation from  
                         * occurring.  These problems are why SQL-2003 similarly specifies  
                         * that for SQL MERGE, an exception must be raised in the event of  
                         * an attempt to update the same row twice.  

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

例子

postgres=# \set VERBOSITY verbose  
  
postgres=# insert into t_conf select * from (values (1,'test'), (1,'test1')) t(id,info) on conflict(id) do update set info=excluded.info;  
ERROR:  21000: ON CONFLICT DO UPDATE command cannot affect row a second time  
HINT:  Ensure that no rows proposed for insertion within the same command have duplicate constrained values.  
LOCATION:  ExecOnConflictUpdate, nodeModifyTable.c:1259  
  
postgres=# insert into t_conf values (1,'test'), (1,'test1') on conflict(id) do update set info=excluded.info;  
ERROR:  21000: ON CONFLICT DO UPDATE command cannot affect row a second time  
HINT:  Ensure that no rows proposed for insertion within the same command have duplicate constrained values.  
LOCATION:  ExecOnConflictUpdate, nodeModifyTable.c:1259  

报错代码

src/backend/executor/nodeModifyTable.c

/*  
 * ExecOnConflictUpdate --- execute UPDATE of INSERT ON CONFLICT DO UPDATE  
 *  
 * Try to lock tuple for update as part of speculative insertion.  If  
 * a qual originating from ON CONFLICT DO UPDATE is satisfied, update  
 * (but still lock row, even though it may not satisfy estate's  
 * snapshot).  
 *  
 * Returns true if if we're done (with or without an update), or false if  
 * the caller must retry the INSERT from scratch.  
 */  
static bool  
ExecOnConflictUpdate(ModifyTableState *mtstate,  
                                         ResultRelInfo *resultRelInfo,  
                                         ItemPointer conflictTid,  
                                         TupleTableSlot *planSlot,  
                                         TupleTableSlot *excludedSlot,  
                                         EState *estate,  
                                         bool canSetTag,  
                                         TupleTableSlot **returning)  
{  
.....................  
                case HeapTupleInvisible:  
  
                        /*  
                         * This can occur when a just inserted tuple is updated again in  
                         * the same command. E.g. because multiple rows with the same  
                         * conflicting key values are inserted.  
                         *  
                         * This is somewhat similar to the ExecUpdate()  
                         * HeapTupleSelfUpdated case.  We do not want to proceed because  
                         * it would lead to the same row being updated a second time in  
                         * some unspecified order, and in contrast to plain UPDATEs  
                         * there's no historical behavior to break.  
                         *  
                         * It is the user's responsibility to prevent this situation from  
                         * occurring.  These problems are why SQL-2003 similarly specifies  
                         * that for SQL MERGE, an exception must be raised in the event of  
                         * an attempt to update the same row twice.  
                         */  
                        if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple.t_data)))  
                                ereport(ERROR,  
                                                (errcode(ERRCODE_CARDINALITY_VIOLATION),  
                                                 errmsg("ON CONFLICT DO UPDATE command cannot affect row a second time"),  
                                                 errhint("Ensure that no rows proposed for insertion within the same command have duplicate constrained values.")));  
  
                        /* This shouldn't happen */  
                        elog(ERROR, "attempted to lock invisible tuple");  

PostgreSQL 不处理这种错误,应该让用户自己来保障,不会在同一条SQL中出现多条同一个KEY的TUPLE。

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
5月前
|
关系型数据库 PostgreSQL
postgresql insert into插入记录时使用select子查询
postgresql insert into插入记录时使用select子查询
|
关系型数据库 PostgreSQL
PostgreSQL INSERT INTO 语句
PostgreSQL INSERT INTO 语句
276 0
|
SQL 弹性计算 关系型数据库
PostgreSQL 大宽表,全列索引,高并发合并写入(insert into on conflict, upsert, merge insert) - 实时adhoc query
标签 PostgreSQL , 全列索引 , 大宽表 , 写测试 , insert on conflict , upsert , merge insert , adhoc query 背景 OLAP系统中,adhoc query非常场景(任意维度查询分析)。 adhoc query,通常来说,可以加GIN倒排,或者每一列都加一个索引来实现。 《PostgreSQL 设计优化case
8421 0
|
弹性计算 关系型数据库 测试技术
PostgreSQL 分区表如何支持多列唯一约束 - 枚举、hash哈希 分区, 多列唯一, insert into on conflict, update, upsert, merge insert
标签 PostgreSQL , 分区表 , native partition , 唯一 , 非分区键唯一 , 组合唯一 , insert into on conflict , upsert , merge insert 背景 PG 11开始支持HASH分区,10的分区如果要支持hash分区,可以通过枚举绕道实现。 《PostgreSQL 9.x, 10, 11 hash分区表 用法举例
2909 0
|
Web App开发 SQL 关系型数据库
Locking issue with concurrent DELETE / INSERT in PostgreSQL - 解法 advisory lock
标签 PostgreSQL , 原子性 , 并行锁同行 , advisory lock 背景 两个会话,同时对同一个ID值的记录执行删除后插入,有一个会话会出现删除0,插入失败的现象。 现象 CREATE TABLE test (id INT PRIMARY KEY); INSER...
849 0
|
关系型数据库 PostgreSQL
PostgreSQL merge insert(upsert/insert into on conflict) 如何区分数据是INSERT还是UPDATE
标签 PostgreSQL , merge insert , upsert , insert into on conflict , 区分 insert update , xmin , xmax 背景 使用insert into on conflict update语法,可以支持UPSERT的功能,但是到底这条SQL是插入的还是更新的呢?如何判断 通过xmax字段的值是否不为0,可以判断,如果是UPDATE,XMAX里面会填充更新事务号。
2054 0
|
关系型数据库 PostgreSQL 测试技术
|
SQL 关系型数据库 PostgreSQL

相关产品

  • 云原生数据库 PolarDB