sql - Upsert/on 与串行主键冲突

标签 sql postgresql

更新插入在冲突时有效,但 id 的数据类型是串行的,这意味着我想让它自动生成/递增。如果我在不指定 id 的情况下执行插入,则插入工作正常。

我遇到的问题是将两者结合起来。为了让 key 自动递增,我没有将 id 传递到插入中,但如果我不传递 id 那么更新将永远不会触发。我不能将 null 传递给 id,因为它是非空字段。

在下面的示例中 - 我第一次运行查询,它执行插入,第二次执行更新,但我无法弄清楚如何将“无”传递给插入,因此身份 key 在插入时仍然有效。我可以将 DEFAULT 放入插入中,但如果有的话,我就无法传递真实的 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_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。此外,更新现在也使用您的参数。

关于sql - Upsert/on 与串行主键冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51708197/

相关文章:

mysql - 检查数字是否在由分隔符分隔的字符串中

MySQL 将 1 行链接到多个

Sql 范围组开始和结束 ID

arrays - Postgres,找到数组列的最小值并获得它的位置

sql - SQL 中的唯一访问次数

sql - 没有结果的 Where 子句

arrays - Hibernate SQLQuery,如何获取数组和行对象?

mysql - SQL 日期范围比较 资源预订冲突 重复结果

sql - 如何在sql中使用一个公共(public)列以不同的条件两次使用同一列

mysql - 试图从数据库返回行号的语法错误