可写CTE被认为是9.5之前UPSERT的解决方案,如Insert, on duplicate update in PostgreSQL?所述

可以使用以下可写CTEs惯用语执行UPSERT,其中包含的信息是作为更新还是插入结束的:

WITH
    update_cte AS (
        UPDATE t SET v = $1 WHERE id = $2 RETURNING 'updated'::text status
    ),
    insert_cte AS (
        INSERT INTO t(id, v) SELECT $2, $1 WHERE NOT EXISTS
            (SELECT 1 FROM update_cte) RETURNING 'inserted'::text status
    )
 (SELECT status FROM update_cte) UNION (SELECT status FROM insert_cte)

此查询将返回"已更新"或"已插入",或者可能(很少)因违反中的约束而失败,如https://dba.stackexchange.com/questions/78510/why-is-cte-open-to-lost-updates中所述

使用PostgreSQL 9.5+新的"UPSERT"语法,从优化中获益,避免可能的约束冲突,可以实现类似的功能吗?

推荐答案

我相信xmax::text::int > 0是最简单的把戏:

so=# DROP TABLE IF EXISTS tab;
NOTICE:  table "tab" does not exist, skipping
DROP TABLE
so=# CREATE TABLE tab(id INT PRIMARY KEY, col text);
CREATE TABLE
so=# INSERT INTO tab(id, col) VALUES (1,'a'), (2, 'b');
INSERT 0 2
so=# INSERT INTO tab(id, col)
VALUES (3, 'c'), (4, 'd'), (1,'aaaa')
ON CONFLICT (id) DO UPDATE SET col = EXCLUDED.col
returning *,case when xmax::text::int > 0 then 'updated' else 'inserted' end,ctid;
 id | col  |   case   | ctid
----+------+----------+-------
  3 | c    | inserted | (0,3)
  4 | d    | inserted | (0,4)
  1 | aaaa | updated  | (0,5)
(3 rows)

INSERT 0 3
so=# INSERT INTO tab(id, col)
VALUES (3, 'c'), (4, 'd'), (1,'aaaa')
ON CONFLICT (id) DO UPDATE SET col = EXCLUDED.col
returning *,case when xmax::text::int > 0 then 'updated' else 'inserted' end,ctid;
 id | col  |  case   | ctid
----+------+---------+-------
  3 | c    | updated | (0,6)
  4 | d    | updated | (0,7)
  1 | aaaa | updated | (0,8)
(3 rows)

INSERT 0 3

Postgresql相关问答推荐

PostgreSQL散列连接与嵌套循环和散列索引

包含JSONB属性的过滤器的索引策略

带有附加组的时间刻度 interpolated_average

为什么在 PostgreSQL 中忽略查询超时?

PostgreSQL - 改变数字的精度?

在postgresql中按经纬度查找最近的位置

如何从 postgresql Select 查询中的 age() 函数中仅获取年份

带有 -C 选项的 pg_restore 不会创建数据库

在 PostgreSQL 中将时间转换为秒

postgresql 在查询中插入空值

'active' 标志与否?

使用 postgres regexp_replace 将字符串列表替换为始终相同的字符串

psql:致命:connection requires a valid client certificate

错误:CASE types character varying and numeric cannot be matched

如何使用 psql 命令列出、创建、使用和判断数据库?

仅当 PostgreSQL 表不存在时才添加主键

如何使用 Django Migrations 重新创建已删除的表?

在 Flask-sqlalchemy 和 Postgresql 中使用 JSON 类型

Rails 5 db 迁移:如何修复 ActiveRecord::ConcurrentMigrationError

PostgreSQL 中具有多个连接的 UPDATE 语句