(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;
规避问题,但我仍然得到这些错误 - 任何想法为什么?
答案 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;