postgresql Postgres在ON CONFLICT中使用两列会发生错误

qlckcl4x  于 2023-03-12  发布在  PostgreSQL
关注(0)|答案(3)|浏览(548)

我使用查询字符串:

INSERT INTO public.owner (name, address, public_key) 
VALUES 
('name1', 'address4', 'publicKey1'),
('name1', 'address5', 'publicKey2'),
('name1', 'address6', 'publicKey3')

ON CONFLICT (address, public_key) DO NOTHING;

我收到一条错误信息:

ERROR:  there is no unique or exclusion constraint matching the ON CONFLICT specification
SQL state: 42P10

我知道另一个类似问题的答案是在列的表中添加UNIQUE CONSTRAINT,但我已经这样做了,错误仍然存在。
我的创建脚本是:

CREATE TABLE IF NOT EXISTS public.owner
(
    id integer NOT NULL DEFAULT nextval('owner_id_seq'::regclass),
    name character varying COLLATE pg_catalog."default" NOT NULL,
    address character varying COLLATE pg_catalog."default" NOT NULL,
    public_key character varying COLLATE pg_catalog."default" NOT NULL,
    created_at timestamp without time zone NOT NULL DEFAULT now(),
    updated_at timestamp without time zone NOT NULL DEFAULT now(),
    CONSTRAINT "PK_8e86b6b9f94aece7d12d465dc0c" PRIMARY KEY (id),
    CONSTRAINT "UQ_5e67355720891990b30c3079806" UNIQUE (address),
    CONSTRAINT "UQ_dbff2cddd177bff09af6381696d" UNIQUE (public_key)
)

CONSTRAINT "UQ_5e67355720891990b30c3079806" UNIQUE (address)"UQ_dbff2cddd177bff09af6381696d" UNIQUE (public_key)已在表中创建。
但是查询字符串仍然不起作用。
有什么错误我没改正吗?

cbeh67ev

cbeh67ev1#

conflict_target只能处理一个潜在的冲突,这意味着您必须在address或public_key的唯一约束或这两列的组合之间做出选择。
使用ONCONFLICT子句的当前实现无法处理多个约束冲突。

ou6hu8tu

ou6hu8tu2#

你不需要每个键都有一列,你需要一个键有两列。
或者,on conflict子句应该只提到一列。

create table ownerTwoKeys(
    name varchar(30),
    address varchar(30),
    public_key varchar(30),
    CONSTRAINT UQ_address UNIQUE (address),
    CONSTRAINT UQ_public_key UNIQUE (public_key)
);

create table ownerOneKey (
    name varchar(30),
    address varchar(30),
    public_key varchar(30),
    CONSTRAINT UQ_address_public_key UNIQUE (address, public_key)
  
);

INSERT INTO ownerTwoKeys (name, address, public_key) 
VALUES 
('name1', 'address4', 'publicKey1'),
('name1', 'address5', 'publicKey2'),
('name1', 'address6', 'publicKey3'),
('name1', 'address7', 'publicKey4'),
('name1', 'address6', 'publicKey5')
ON CONFLICT (address) DO NOTHING;

select * from ownerTwoKeys;


INSERT INTO ownerOneKey (name, address, public_key) 
VALUES 
('name1', 'address4', 'publicKey1'),
('name1', 'address5', 'publicKey2'),
('name1', 'address6', 'publicKey3'),
('name1', 'address7', 'publicKey4'),
('name1', 'address6', 'publicKey4'),
('name2', 'address6', 'publicKey4')
ON CONFLICT (address, public_key) DO NOTHING;

select * from ownerOneKey;

DB fiddle to play with .

c9x0cxw0

c9x0cxw03#

pointed out by Frank Heikens一样,不能在一个on conflict子句中处理多个冲突场景。
幸运的是,有一个例外:
对于ON CONFLICT DO NOTHING,可选指定conflict_target;当省略时,处理与所有可用约束(和唯一索引)的冲突。
因此,您可以跳过冲突目标列表:online demo

INSERT INTO public.owner (name, address, public_key) 
VALUES 
('name1', 'address4', 'publicKey1'),
('name1', 'address5', 'publicKey2'),
('name1', 'address6', 'publicKey3')
ON CONFLICT /*no targets specified*/ DO NOTHING;

这对这种特殊情况有效,因为只有3个约束,其中2个您希望以这种方式处理,剩下的1个通过让目标表自己生成唯一的id来处理。

  • 如果您有更多的约束,并且只想跳过这两个,on conflict do nothing仍然会跳过它们。
  • 如果你想使用on conflict do update以特定的方式解决冲突,你必须指定解决方案所针对的一个约束。要解决更多的约束,你需要“手动”避免它们,首先在传入数据中发现冲突,然后在插入之前过滤掉它们,如here所示。

相关问题