Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql Upsert/on与串行主键冲突_Sql_Postgresql - Fatal编程技术网

Sql Upsert/on与串行主键冲突

Sql Upsert/on与串行主键冲突,sql,postgresql,Sql,Postgresql,upsert使用onconflict工作,但id的数据类型是serial,这意味着我希望它自动生成/递增。如果我在不指定id的情况下进行插入,则插入工作正常 我的问题是将两者结合起来。要使密钥自动递增,我不会将id传递到insert中,但如果我不传递id,则更新将永远不会触发。我不能将null传递给id,因为它是非null字段 在下面的示例中-我第一次运行查询,它确实插入,第二次它确实更新,但我不知道如何传递“nothing”以插入,因此标识键仍然可以在插入时工作。我可以在insert中设置默认

upsert使用onconflict工作,但id的数据类型是serial,这意味着我希望它自动生成/递增。如果我在不指定id的情况下进行插入,则插入工作正常

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

在下面的示例中-我第一次运行查询,它确实插入,第二次它确实更新,但我不知道如何传递“nothing”以插入,因此标识键仍然可以在插入时工作。我可以在insert中设置默认值,但是如果有实际的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;

您可以将查询更改为使用序列函数,如:

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\u test\u id\u 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;

注意,我添加了这个函数,所以如果您的参数为null,那么使用sequence nextval。此外,更新现在还使用您的参数。

谢谢您的回复。我想我需要在提交到查询之前测试'id'变量,如果它为null,那么我会按照您的建议将其更改为nextval函数。我希望不必操纵id值,但这似乎会奏效。谢谢,我不清楚你想要空支票,我更新了答案。是的,效果很好。我尝试了值(COALESCE(:YOUR_ID_PARAM,(Default)),'thing1','test'),但在这个上下文中它似乎不喜欢默认值。谢谢