Postgres 9.5+:UPSERT返回更新和插入行的计数

ssc*_*zio 13 postgresql upsert

我得到了一个典型的例子:

 INSERT INTO user_logins (username, logins)
 VALUES ('Naomi',1),('James',1)
 ON CONFLICT (username)
 DO UPDATE SET logins = user_logins.logins + EXCLUDED.logins;
Run Code Online (Sandbox Code Playgroud)

但现在我还需要知道:

  1. 插入了多少行
  2. 由于存在,已更新了多少行
  3. 由于约束,无法插入多少行
  4. 如果最后一行不遵守约束,先前插入/更新的行是否会保留在DB中?

Rhi*_*him 11

我不知道你怎么能理解发生了什么事.您应该查看xmax的值,如果xmax = 0表示插入了行,则其他值xmax就行更新.

我的英语不好,我会尝试展示这个例子.

create table test3(r1 text unique, r2 text);
\d+ test3
                       Table "public.test3"
 Column | Type | Modifiers | Storage  | Stats target | Description 
--------+------+-----------+----------+--------------+-------------
 r1     | text |           | extended |              | 
 r2     | text |           | extended |              | 
Indexes:
    "test3_r1_key" UNIQUE CONSTRAINT, btree (r1)
Run Code Online (Sandbox Code Playgroud)

插入

INSERT INTO test3 
VALUES('www7','rrr'), ('www8','rrr2') 
ON CONFLICT (r1) DO UPDATE SET r2 = 'QQQQ' RETURNING xmax;
 xmax 
------
    0
    0
Run Code Online (Sandbox Code Playgroud)

如果您尝试插入副本:

INSERT INTO test3 
VALUES('www7','rrr'), ('www8','rrr2') 
ON CONFLICT (r1) DO UPDATE SET r2 = 'QQQQ' RETURNING xmax;
   xmax    
-----------
 430343538
 430343538
(2 rows)

INSERT 0 2
Run Code Online (Sandbox Code Playgroud)

结果可以通过以下方式处理:
插入1个新行和1个重复行

WITH t AS  (
  INSERT INTO test3 
  VALUES('www9','rrr'), ('www7','rrr2') 
  ON CONFLICT (r1) DO UPDATE SET r2 = 'QQQQ' RETURNING xmax
) 
SELECT COUNT(*) AS all_rows, 
       SUM(CASE WHEN xmax = 0 THEN 1 ELSE 0 END) AS ins, 
       SUM(CASE WHEN xmax::text::int > 0 THEN 1 ELSE 0 END) AS upd 
FROM t;

all_rows  | ins | upd 
----------+-----+-----
        2 |   1 |   1
Run Code Online (Sandbox Code Playgroud)

5.4.系统列MVCC

非常有趣的是如何更优雅地解决问题

  • @Gerhard 干得漂亮,我当时没有想到这一点。我首先想到的就是将其转换为必要的类型。 (2认同)