Почему это правило не предотвращает повторные нарушения ключа? - PullRequest
8 голосов
/ 11 марта 2011

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

10 голосов
/ 11 марта 2011

Правила по умолчанию добавляют вещи к текущему действию :

Грубо говоря, правило приводит к выполнению дополнительных команд при выполнении данной команды в данной таблице.

Но правило INSTEAD позволяет заменить действие:

В качестве альтернативы правило INSTEAD может заменить данную команду другой или заставить команду не выполнятьсявообще.

Итак, я думаю, вы хотите, чтобы указывал 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и затем ничего не делать «когда вы хотите сказать» вместо ВСТАВКИ, ничего не делать », и, AFAIK, DO INSTEAD NOTHING сделает это.

Я не эксперт по правилам PostgreSQL, но я думаю, что добавление«INSTEAD» должен работать.

ОБНОВЛЕНИЕ : Благодаря araqnid мы знаем, что :

COPY FROM вызовет любые триггеры ипроверить ограничения в таблице назначения.Однако он не будет вызывать правила

, поэтому правило не будет работать в этой ситуации.Тем не менее, триггеры запускаются во время COPY FROM, поэтому вы можете написать триггер BEFORE INSERT , который будет возвращать NULL при обнаружении повторяющихся строк:

Он может вернуть NULL, чтобы пропустить операциютекущий ряд.Это указывает исполнителю не выполнять операцию на уровне строк, которая вызвала триггер (вставка или изменение определенной строки таблицы).

Тем не менее, я думаю, что вам лучше использовать araqnid«загрузить все это во временную таблицу, очистить и скопировать в конечный пункт назначения» было бы более разумным решением для такой операции массовой загрузки, как у вас.

5 голосов
/ 11 марта 2011

COPY FROM не будет вызывать правила (http://www.postgresql.org/docs/9.0/interactive/sql-copy.html#AEN58860)

Мой подход заключается в том, чтобы загрузить данные CSV во временную таблицу, а затем использовать оператор INSERT...SELECT, чтобы скопировать данные в целевую таблицу, где она не 't уже существует. (Если в самих данных 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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...