PostgreSQL Upsert在分区表上不起作用


9

有一个这样的表:

CREATE TABLE aggregated_master (
  "user"       BIGINT,
  type         TEXT,
  date         TIMESTAMP,
  operations   BIGINT,
  amount       NUMERIC,
  PRIMARY KEY ( "user", type, date )
);

该表是从中继承许多分区的主表。分区由DATE字段中的MONTH完成。例如:2017年8月的分区将是agg_201708,它的PK将是pk_agg_201708。在插入之前,通常有触发器将插入重定向到适当的分区。

事情是我想对这张表做一个UPSERT。DO CONFLICT部分不起作用。

代码首先是这样的

INSERT INTO aggregated_master (user, type, date, oeprations, amount)
SELECT user, type, date, SUM(ops), SUM(amt)
FROM ...
WHERE ...
GROUP BY USER, TYPE, DATE
ON CONFLICT ON CONSTRAINT pk_aggregated
DO UPDATE SET operations = EXCLUDED.operations
          ,   amount = EXCLUDED.amount

但是后来我注意到,由于触发器的原因,约束(pk_aggregated)是主表上的约束,而不是将真正执行插入的子表上的约束。

我将CONFLICT条款更改为:

ON CONFLICT (user, type, date)

哪些是PK的字段,但这也不起作用。

任何想法如何使这项工作?


2
不要以为实施会受到限制。它应该真正检测到该错误。报告错误?
Craig Ringer

5
又见这个邮件列表线程postgresql.org/message-id/...
克雷格·林格

Answers:


6

PostgreSQL 11支持INSERT INTO ... ON CONFLICT分区表:

CREATE TABLE o(id INT PRIMARY KEY, i INT) PARTITION BY RANGE (id);

CREATE TABLE o1 PARTITION OF o FOR VALUES FROM (1) TO (1000);
CREATE TABLE o2 PARTITION OF o FOR VALUES FROM (1000) TO (2000);

INSERT INTO o(id, i) VALUES (1,1),(2,2),(1500,1500);

INSERT INTO o(id, i)
VALUES (1500, 1400), (2,20), (3, 3)
ON CONFLICT (id)
DO UPDATE SET i = EXCLUDED.i;

SELECT * FROM o;

DBFiddle演示


限制ddl分区

5.10.2.3。局限性

在分区表上使用ON CONFLICT子句将导致错误,因为唯一约束或排除约束只能在单个分区上创建。不支持在整个分区层次结构中强制唯一性(或排除约束)。

已解除。


11

在Postgres 11之前的版本中未实现对分区表的更新。

在Postgres 9.6中:

带有ON CONFLICT子句的INSERT语句不太可能按预期工作,因为ON CONFLICT动作仅在指定目标关系(而不是其子关系)发生唯一违反的情况下才采取。

声明式分区不能解决问题,Postgres 10:

在分区表上使用ON CONFLICT子句将导致错误,因为唯一约束或排除约束只能在单个分区上创建。不支持在整个分区层次结构中强制唯一性(或排除约束)。

解决方法

在Postgres 11中,您可以ON CONFLICT在分区表上使用,请参阅lad2025的答案。


如@ lad2025所述,需要针对确实实现了它的pg11更新此答案。
DB140141,19年

@ DB140141-thx,答案已更新。
klin
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.