2011-03-11 88 views
8

(PostgreSQL的),我试图COPY CSV数据到表中,但我得到的重复键冲突错误,而且也没有办法告诉COPY忽视这些,所以下面的互联网智慧我尝试添加这条规则:为什么这个规则不能防止重复键违规?

CREATE OR REPLACE RULE ignore_duplicate_inserts AS 
    ON INSERT TO mytable 
    WHERE (EXISTS (SELECT mytable.id 
      FROM mytable 
      WHERE mytable.id = new.id)) DO NOTHING; 

来规避问题,但我仍然得到这些错误 - 任何想法为什么?

回答

10

规则默认add things to the current action

粗略地说,一个规则使得执行在给定的表给定的命令时执行的其他命令。

但是,一个INSTEAD规则允许您更换行动:

另外,一个INSTEAD规则可以用另外一个替换给定的命令,或者导致无法在所有执行的命令。

所以,我想你想要to specify INSTEAD

CREATE OR REPLACE RULE ignore_duplicate_inserts AS 
    ON INSERT TO mytable 
    WHERE (EXISTS (SELECT mytable.id 
      FROM mytable 
      WHERE mytable.id = new.id)) DO INSTEAD NOTHING; 

没有相反,你的规则基本上等于在说“做插入,然后什么也不做”,当你想说“,而不是INSERT,什么都不做“,AFAIK,DO INSTEAD NOTHING将做到这一点。

我不是PostgreSQL规则的专家,但我认为添加“INSTEAD”应该可以工作。

UPDATE:感谢araqnid we know that

COPY FROM会激活所有触发器和检查目标表的约束。但是,它不会调用规则

因此,在这种情况下规则不起作用。然而,触发器COPY FROM,所以你可以写在发射的前插入trigger that would return NULL,当它检测到重复行:

它可以返回NULL来忽略操作当前行。这指示执行程序不执行调用触发器的行级操作(插入或修改特定的表行)。

这么说,我想你会与araqnid的更好“这一切都加载到一个临时表,把它清理干净,并将其复制到最终目标”将是一个批量加载一个更明智的解决方案像你一样操作。

+2

这将适用于实际的INSERT语句,但不适用于COPY。 – araqnid 2011-03-11 11:41:14

+1

@araqnid:“COPY FROM将调用目标表上的任何触发器并检查约束,但它不会调用规则。”您可以使用BEFORE INSERT触发器并返回NULL来跳过重复项。 OTOH,触发器可能不是处理批量数据加载的最佳工具。 – 2011-03-11 21:02:52

5

COPY FROM不会激活规则(http://www.postgresql.org/docs/9.0/interactive/sql-copy.html#AEN58860)

我的做法是将CSV数据装载到一个临时表,然后使用INSERT...SELECT语句将数据复制到尚不存在的目标表中。 (如果CSV数据本身存在重复,请首先从临时表中删除这些重复项)。例如:

BEGIN; 
CREATE TEMP TABLE stage_data(key_column, data_columns...) ON COMMIT DROP; 
\copy stage_data from data.csv with csv header 
-- prevent any other updates while we are merging input (omit this if you don't need it) 
LOCK target_data IN SHARE ROW EXCLUSIVE MODE; 
-- insert into target table 
INSERT INTO target_data(key_column, data_columns...) 
    SELECT key_column, data_columns... 
    FROM stage_data 
    WHERE NOT EXISTS (SELECT 1 FROM target_data 
        WHERE target_data.key_column = stage_data.key_column) 
END; 
+0

“选择不同”来提供插入将有所作为,除了重复项可能已经在target_data中。为了一次清理一组数据,它将起作用。 – 2018-02-27 17:43:39

相关问题