【发布时间】:2020-12-20 06:15:44
【问题描述】:
考虑下表:
CREATE TABLE key_phrase(
id SERIAL PRIMARY KEY NOT NULL,
body TEXT UNIQUE
)
我想做以下事情:
- 使用给定的
body创建一条记录如果它尚不存在。 - 返回新创建记录的id,如果没有创建新记录,则返回现有记录的id。
- 确保序列id在冲突时不递增。
我尝试了几种方法,最简单的包括DO NOTHING的基本用法:
INSERT INTO key_phrase(body) VALUES ('example') ON CONFLICT DO NOTHING RETURNING id
但是,如果创建了新记录,这只会返回 id。
我还尝试了以下方法:
WITH ins AS (
INSERT INTO key_phrase (body)
VALUES (:phrase)
ON CONFLICT (body) DO UPDATE
SET body = NULL
WHERE FALSE
RETURNING id
)
SELECT id FROM ins
UNION ALL
SELECT id FROM key_phrase
WHERE body = :phrase
LIMIT 1;
这将返回新创建记录的 id 或现有记录的 id。但是,它会导致串行主节点发生碰撞,从而在创建新记录时产生间隙。
那么如何执行满足前面提到的 3 个要求的条件插入(upsert)?
【问题讨论】:
-
无论你尝试什么,使用连续剧总是会给你一个机会在编号中出现漏洞。没有办法避免这种情况,除非您继续检查和更改底层序列。来自手册:因为 smallserial、serial 和 bigserial 是使用序列实现的,所以即使没有删除任何行,列中出现的值序列也可能存在“漏洞”或间隙。
标签: sql postgresql sql-update sql-insert knex.js