postgresql Postgres插入冲突和外键检查

7lrncoxx  于 2023-10-18  发布在  PostgreSQL
关注(0)|答案(2)|浏览(142)

查询方式:

INSERT INTO
   derived (a, b, c)
VALUES (?, ?, ?)
ON CONFLICT (a, b, c) DO UPDATE SET
   a = EXCLUDED.a,
   b = EXCLUDED.b,
   c = EXCLUDED.c
WHERE EXISTS (select a from primary where a = ?)

请注意

  • 第四参数与第一参数相同。
  • derived. a在primary. a上有foreign-key-constraint
  • 如果所有3列都有冲突,则必须进行更新。

不幸的是,这个查询不起作用,当插入一个不在主表中的值a时,我仍然会得到一个外键冲突。任何帮助都是感激不尽的。

xhv8bpkk

xhv8bpkk1#

以下是我想要的:

WITH data_table (a, b, c)
  AS (
    values (?, ?, ?)
  )
INSERT INTO derived (a, b, c)
SELECT dt.a, dt.b, dt.c
FROM data_table dt
WHERE EXISTS (select a from primary where a = ?)
ON CONFLICT (a, b, c) DO UPDATE SET
   a = EXCLUDED.a,
   b = EXCLUDED.b,
   c = EXCLUDED.c
kxkpmulp

kxkpmulp2#

你的解决方案,同时给出你想要的结果是过于复杂,因为它本质上是:

insert into
   derived (a, b, c)
values (?, ?, ?)
on conflict (a, b, c) do nothing;

让我们分析你的解决方案,看看为什么。首先,你的表必须看起来像这样:

create table primary_tbl (a   integer  generated always as identity
                                       primary key
                         ,name text not null
                          );

create table derived (a  integer references primary_tbl(a) 
                     ,b  integer 
                     ,c  integer
                     ,constraint derived_uk unique (a,b,c)
                     );

现在,实际的数据类型和约束类型并不重要,只是a在每个表中必须是相同的类型,并且在表中必须是唯一的。那么3列组合必须在derived中形成唯一组合。
现在,为了获得所有3个值的冲突,以正确的顺序必须已经存在于derived中,因此您的更新操作只是将每个列设置为它已经拥有的相同值(是的,将列设置为当前值实际上会更新该列)。最后,关于where子句。如果derived.a的匹配值在primary.a中不存在,那么由于it的定义为外键,该行就不存在。因此,由于数据值相同,并且where必须返回true,因此行内容完全相同。这就是do nothing子句的结果。所以:

insert into derived (a, b, c)
  values (?,?,?)
  on conflict (a, b, c) 
  do nothing;

如果涉及到另一个非键列(称之为d),情况就会发生变化。在这种情况下,您只需要设置d更新阶段的值,您不需要更新列abc-它们已经退出。

insert into derived(a,b,c,d)
  values (?,?,?,?) 
 on conflict (a,b,c) 
 do update 
       set d = excluded.d;

请参见demo here

相关问题