Upsert / on与串行主键冲突

时间:2018-08-06 12:56:24

标签: sql postgresql

upsert在冲突时使用,但是id的数据类型是串行的,这意味着我想让它自动生成/增加。如果我在未指定id的情况下进行插入,则插入效果很好。

我遇到的问题是将两者结合在一起。要使密钥自动递增,我不会将ID传递到插入内容中,但是如果我不传递ID,则更新将永远不会触发。我不能将null传递给id,因为它是非null字段。

在下面的示例中-我第一次运行查询,并且确实插入并且第二次更新,但是我无法弄清楚如何通过“ nothing”插入,因此身份密钥仍然适用于插入。我可以将DEFAULT插入到插入中,但是如果有一个ID,我就不能传递真实的ID。

CREATE TABLE public.upsert_test
(
    id INTEGER NOT NULL DEFAULT nextval('upsert_test_id_seq'::regclass),
    name character varying(20) COLLATE pg_catalog."default",
    description character varying(20) COLLATE pg_catalog."default",
    CONSTRAINT upsert_test_pkey PRIMARY KEY (id)
)

INSERT INTO upsert_test (id, name, description)
VALUES (1, 'thing1', 'test')
on conflict (id)
do update set (name , description) = ('thing_updated','test-updated')   
where upsert_test.id = 1;

1 个答案:

答案 0 :(得分:0)

您可以更改查询以使用诸如以下的序列函数:

INSERT INTO upsert_test (id, name, description)
VALUES ((select nextval('upsert_test_id_seq')), 'thing1', 'test')
on conflict (id)
do update set (name , description) = ('thing_updated','test-updated')   
where upsert_test.id = (select currval('upsert_test_id_seq'));

请注意,这可能不是线程安全的,例如,如果在第一次调用的select currval('upsert_test_id_seq')之前执行了对该SQL的第二次调用,则更新可能会在第一次查询中失败。

从op获得更多信息后更新

您可以将查询更改为这样:

INSERT INTO upsert_test (id, name, description)
VALUES (COALESCE(:YOUR_ID_PARAM, (select nextval('upsert_test_id_seq'))), 'thing1', 'test')
on conflict (id)
do update set (name , description) = ('thing_updated','test-updated')   
where upsert_test.id = :YOUR_ID_PARAM;

请注意,我添加了coalesce函数,因此如果您的参数为null,则使用序列nextval。此外,此更新现在还使用了您的参数。