为什么此规则不能防止重复的密钥违规?

时间:2011-03-11 06:13:53

标签: postgresql insert copy duplicates rules

(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;

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

2 个答案:

答案 0 :(得分: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;

如果没有INSTEAD,当你想说“而不是INSERT,什么也不做”时,你的规则实际上是说“做INSERT然后什么也不做”,而AFAIK,DO INSTEAD NOTHING会这样做。< / p>

我不是PostgreSQL规则的专家,但我认为添加“INSTEAD”应该有效。

更新:感谢araqnid we know that

  

COPY FROM将调用任何触发器并检查目标表上的约束。但是,它不会调用规则

所以规则在这种情况下不会起作用。但是,在COPY FROM期间会触发触发器,因此您可以在检测到重复行时编写BEFORE INSERT trigger that would return NULL

  

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

那就是说,我认为你最好用araqnid“将它全部加载到临时表中,清理它并将其复制到最终目的地”对于像你这样的批量加载操作来说​​是一个更明智的解决方案有

答案 1 :(得分: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;