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

时间:2016-08-09 12:48:30

标签: 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;

但现在我还需要知道:

  1. 插入了多少行
  2. 因为现有
  3. 而更新了多少行
  4. 由于约束而无法插入多少行
  5. 如果最后一行没有遵守约束,先前插入/更新的行是否会保留在数据库中?

1 个答案:

答案 0 :(得分:10)

我不知道你怎么能理解发生了什么事。 您应该查看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)

INSERT

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

如果您尝试插入副本:

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

结果可以这样处理:
插入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

请参阅5.4. System Columns MVCC

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