sql - 从条件 INSERT 中获取 Id

标签 sql postgresql concurrency upsert

对于像这样的表:

CREATE TABLE Users(
    id SERIAL PRIMARY KEY,
    name TEXT UNIQUE
);

以下操作的正确单查询插入是什么:

给定一个用户name,插入一条新记录并返回新的id。但如果 name 已经存在,则返回 id

我知道 PostgreSQL 9.5 中用于 ON CONFLICT(column) DO UPDATE/NOTHING 的新语法,但我无法弄清楚它如何(如果有的话)提供帮助,因为我需要返回 id

看来 RETURNING idON CONFLICT 不属于一起。

最佳答案

UPSERT 实现非常复杂,以防止并发写访问。看看this Postgres Wiki在初始开发期间用作日志。 Postgres 黑客决定不在 Postgres 9.5 的第一个版本的 RETURNING 子句中包含“排除的”行。他们可能会为下一个版本构建一些东西。

这是手册中解释您的情况的关键语句:

The syntax of the RETURNING list is identical to that of the output list of SELECT. Only rows that were successfully inserted or updated will be returned. For example, if a row was locked but not updated because an ON CONFLICT DO UPDATE ... WHERE clause condition was not satisfied, the row will not be returned.

大胆强调我的。

对于要插入的单行:

同一张表上没有并发写入负载

WITH ins AS (
   INSERT INTO users(name)
   VALUES ('new_usr_name')         -- input value
   ON     CONFLICT(name) DO NOTHING
   RETURNING users.id
   )
SELECT id FROM ins
UNION  ALL
SELECT id FROM users          -- 2nd SELECT never executed if INSERT successful
WHERE  name = 'new_usr_name'  -- input value a 2nd time
LIMIT  1;

可能在表上并发写入负载

改为考虑这个(对于单行 INSERT):

要插入一组:

所有这三个都有非常详细的解释。

关于sql - 从条件 INSERT 中获取 Id,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36083669/

相关文章:

java - JPA 中的 PostgreSQL 函数 string_agg

Java 内存可见性和 AtomicReference 的

visual-studio-2010 - Visual Studio 2008对新.NET 4的支持

mysql - 加载数据本地 INFILE 不起作用 - 找不到文件(MySQL Workbench)

postgresql - Postgres 实体化路径 - 使用 ltree 有什么好处?

java - JPQL 查询从一对一关系中选择实体,其中相对的实体具有匹配特定条件的字段

postgresql - 如何在 GCP 的 PostgreSQL 中安装外部扩展

java - 当 Eclipse 中抛出未经检查的异常时,从新创建的线程打印堆栈跟踪

sql - 为什么批量导入比一堆插入更快?

sql - 将表达式转换为数据类型 smallint 时出现算术溢出错误