我有一张桌子,我在 data_id 上有自动编号/序列
tabledata
---------
data_id [PK]
data_code [Unique]
data_desc
Run Code Online (Sandbox Code Playgroud)
示例代码:
insert into tabledata(data_code,data_desc) values(Z01,'red')
on conflict (data_code) do update set data_desc=excluded.data_desc
Run Code Online (Sandbox Code Playgroud)
工作正常,然后我再次插入
insert into tabledata(data_code,data_desc) values(Z01,'blue')
on conflict (data_code) do update set data_desc=excluded.data_desc
Run Code Online (Sandbox Code Playgroud)
我收到这个错误
[Err] 错误:ON CONFLICT DO UPDATE 命令不能再次影响行 提示:确保建议在同一命令中插入的行没有重复的约束值。
这是我的真实代码
insert into psa_aso_branch(branch_code,branch_desc,regional_code,status,created_date,lastmodified_date)
(select branch_code, branch, kode_regional,
case when status_data='Y' then true
else false end, current_date, current_date
from branch_history) on conflict (branch_code) do
update set branch_desc = excluded.branch_desc, regional_code = excluded.regional_code,status = (case when excluded.status='Y' then true else false end), created_date=current_date, lastmodified_date=current_date;
Run Code Online (Sandbox Code Playgroud)
第一个工作正常,但不是下一个(就像我之前给你的例子)
Yak*_*idi 15
我已经被这个问题困扰了大约24小时。
当我在 cli 上测试查询时,它工作正常,这很奇怪。当我使用一个数据行进行插入时,它工作正常。此错误仅在我使用时出现insert-select。
这主要不是因为insert-select问题。这是因为select行不是唯一的。这将CONFLICT多次触发。
感谢@zivaricha 评论。我根据他的笔记进行实验。只是一开始很难理解。
解决方案:使用distinct来确保select返回唯一的结果。
我们可以从源代码中找到错误信息,我们可以简单地理解为什么会出现这样的错误ON CONFLICT DO UPDATE command cannot affect row a second time。
在PostgreSQL的源码src/backend/executor/nodeModifyTable.c和函数中ExecOnConflictUpdate(),我们可以找到这样的注释:
当在同一命令中再次更新刚刚插入的元组时,可能会发生这种情况。例如,因为插入了具有相同冲突键值的多行。
这有点类似于 ExecUpdate() TM_SelfModified 情况。我们不想继续,因为这会导致同一行以某种未指定的顺序第二次更新,并且与普通的 UPDATE 相比,没有需要破坏的历史行为。
正如评论所说,我们无法更新要插入的行INSERT ... ON CONFLICT,就像:
postgres=# CREATE TABLE t (id int primary key, name varchar);
postgres=# INSERT INTO t VALUES (1, 'smart'), (1, 'keyerror')
postgres=# ON CONFLICT (id) DO UPDATE SET name = 'Buuuuuz';
ERROR: 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.
Run Code Online (Sandbox Code Playgroud)
记住,postgresql的执行器是一个火山模型,所以它会一一处理我们插入的数据。当我们处理到(1,'smart')时,由于表是空的,所以可以正常插入。当我们到(1, 'keyerror')时,和我们刚刚插入的(1, 'smart')有冲突,所以执行更新逻辑,导致更新了我们自己插入的数据,而PostgreSQL不会让我们做。
同样,我们不能两次更新同一行数据:
postgres=# DROP TABLE IF EXISTS t;
postgres=# CREATE TABLE t (id int primary key, name varchar);
postgres=# INSERT INTO t VALUES (1, 'keyerror'), (1, 'buuuuz')
postgres=# ON CONFLICT (id) DO UPDATE SET name = 'Buuuuuuuuuz';
ERROR: 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.
Run Code Online (Sandbox Code Playgroud)
您可以在现有记录/行上使用更新,而不是在您插入的行上使用。这里 update inon conflict子句适用于排除表中的行。暂时保留行
在第一种情况下插入记录,因为 data_code 没有冲突。并且根本不执行更新
在第二个插入中,您插入的 Z01 已作为 data_code 插入,并且 data_code 是唯一的。
被排除的表在更新后仍保留 data_code 的重复值。所以没有插入记录。在update setdata_code 中必须更改才能正确插入记录
小智 5
当重复在单个插入中多次发生时,就会出现此错误,
例如您有列 a 、 b 、 c ,并且 a 和 b 的组合是唯一的,并且在重复时您正在更新 c 。现在假设您已经有 a = 1 、 b = 2 、 c = 3 并且您正在插入 a = 1 b = 2 c = 4 和 a = 1 b = 2 c = 4
所以意味着冲突发生两次,因此它无法更新一行两次
| 归档时间: |
|
| 查看次数: |
19982 次 |
| 最近记录: |