2016-09-29 109 views
3

当我尝试在FROM语句中使用多个源时,Postgres 9.5中的ON CONFLICT DO UPDATE存在问题。指向重复约束值的Upsert错误(在冲突时执行更新)

示例工作代码:

INSERT INTO new.bookmonographs (citavi_id, abstract, createdon, edition, title, year) 
SELECT "ID", "Abstract", "CreatedOn"::timestamp, "Edition", "Title", "Year" 
FROM old."Reference" 
WHERE old."Reference"."ReferenceType" = 'Book' 
    AND old."Reference"."Year" IS NOT NULL 
    AND old."Reference"."Title" IS NOT NULL 
ON CONFLICT (citavi_id) DO UPDATE 
    SET (abstract, createdon, edition, title, year) = (excluded.abstract, excluded.createdon, excluded.edition, excluded.title, excluded.year) 
; 

故障代码:

INSERT INTO new.bookmonographs (citavi_id, abstract, createdon, edition, title, year) 
SELECT "ID", "Abstract", "CreatedOn"::timestamp, "Edition", "Title", "Year" 
FROM old."Reference", old."ReferenceAuthor" 
WHERE old."Reference"."ReferenceType" = 'Book' 
    AND old."Reference"."Year" IS NOT NULL 
    AND old."Reference"."Title" IS NOT NULL 
    AND old."ReferenceAuthor"."ReferenceID" = old."Reference"."ID" 
    --Year, Title and Author must be present in the data, otherwise the entry is deemed useless, hence won't be included 
ON CONFLICT (citavi_id) DO UPDATE 
    SET (abstract, createdon, edition, title, year) = (excluded.abstract, excluded.createdon, excluded.edition, excluded.title, excluded.year) 
; 

我在添加另一种原因是语句,并多了一个WHERE语句,以确保只条目有一个标题,年份和作者被插入到新的数据库中。 (如果旧的,“Reference”,“ID”存在于旧的“ReferenceAuthor”中,则为“ReferenceID”,则存在作者)。即使没有额外的WHERE语句,查询也是错误的。我在SELECT中指定的列仅存在于old."Reference"中,而不存在于old."ReferenceAuthor"中。 目前old."ReferenceAuthor"old."Reference"没有唯一约束,对于bookmonographs的潮头约束条件是:

CONSTRAINT bookmonographs_pk PRIMARY KEY (bookmonographsid), 
CONSTRAINT bookmonographs_bookseries FOREIGN KEY (bookseriesid) 
     REFERENCES new.bookseries (bookseriesid) MATCH SIMPLE 
     ON UPDATE NO ACTION ON DELETE NO ACTION, 
CONSTRAINT bookmonographs_citaviid_unique UNIQUE (citavi_id) 

错误PSQL抛出:

ERROR: ON CONFLICT DO UPDATE command cannot affect row a second time HINT: Ensure that no rows proposed for insertion within the same command have duplicate constrained values. ********** Error **********

ERROR: ON CONFLICT DO UPDATE command cannot affect row a second time SQL state: 21000 Hint: Ensure that no rows proposed for insertion within the same command have duplicate constrained values.

我不知道什么是错呢,或者为什么提示指向重复的约束值。

回答

6

的问题是由显然有些条目有多个作者的事实引起的。因此,您在写入的select查询中的内连接将为同一条目返回多行,并且INSERT ... ON CONFLICT不会那样。由于您只使用ReferenceAuthor表进行过滤,因此您可以简单地重写查询,以便它通过在关联的子查询上执行exists来仅过滤没有任何作者的条目。方法如下:

INSERT INTO new.bookmonographs (citavi_id, abstract, createdon, edition, title, year) 
SELECT "ID", "Abstract", "CreatedOn"::timestamp, "Edition", "Title", "Year" 
FROM old."Reference" 
WHERE old."Reference"."ReferenceType" = 'Book' 
    AND old."Reference"."Year" IS NOT NULL 
    AND old."Reference"."Title" IS NOT NULL 
    AND exists(SELECT FROM old."ReferenceAuthor" WHERE old."ReferenceAuthor"."ReferenceID" = old."Reference"."ID") 
    --Year, Title and Author must be present in the data, otherwise the entry is deemed useless, hence won't be included 
ON CONFLICT (citavi_id) DO UPDATE 
    SET (abstract, createdon, edition, title, year) = (excluded.abstract, excluded.createdon, excluded.edition, excluded.title, excluded.year) 
; 
+0

注意:“正常情况下*更新”(最终结果取决于源元组的随机排序)中默认忽略“每个目标的多个更新”。在ON CONFLICT的情况下,每个目标元组的多个源元组将导致递归/级联CONFLICTS(再次:随机顺序问题)或失败(如OQ中)。 – joop

+0

工程就像一个魅力,非常感谢你。什么是你的思维过程来找出错误的原因?或者是否遇到这种问题? – Telefonmann

+0

@Telefonmann我已经意识到这个限制,但是错误信息也很清楚。 – redneb

1

使用一个明确的INNER JOIN加入两个源表一起:

INSERT INTO new.bookmonographs (citavi_id, abstract, createdon, edition, title, year) 
SELECT "ID", "Abstract", "CreatedOn"::timestamp, "Edition", "Title", "Year" 
FROM old."Reference" 
INNER JOIN old."ReferenceAuthor"          -- explicit join 
    ON old."ReferenceAuthor"."ReferenceID" = old."Reference"."ID"  -- ON condition 
WHERE old."Reference"."ReferenceType" = 'Book' AND 
     old."Reference"."Year" IS NOT NULL  AND 
     old."Reference"."Title" IS NOT NULL 
ON CONFLICT (citavi_id) DO UPDATE 
SET (abstract, createdon, edition, title, year) = 
    (excluded.abstract, excluded.createdon, excluded.edition, excluded.title, 
    excluded.year) 
+0

不幸的是,这不起作用,PSQL会引发同样的错误。尽管redneb的解决方案有效。 – Telefonmann