SQL продолжает выполнять запросы после нарушения дубликата ключа - PullRequest
2 голосов
/ 25 июня 2010

У меня есть ситуация, когда я хочу вставить строку, если она не существует, и не вставлять ее, если она уже существует.Я попытался создать sql-запросы, которые предотвратили это (см. здесь ), но мне сказали, что решение состоит в том, чтобы создать ограничения и перехватить исключение при их нарушении.

У меня есть ограниченияуже на месте.У меня вопрос - как я могу перехватить исключение и продолжить выполнение большего количества запросов?Если мой код выглядит следующим образом:

cur = transaction.cursor()

#execute some queries that succeed

try:
    cur.execute(fooquery, bardata)  #this query might fail, but that's OK
except psycopg2.IntegrityError:
    pass

cur.execute(fooquery2, bardata2)

Тогда я получаю сообщение об ошибке при втором выполнении:

psycopg2.InternalError: current transaction is aborted, commands ignored until end of transaction block

Как я могу сказать компьютеру, что я хочу, чтобы он продолжал выполнять запросы?Я не хочу transaction.commit(), потому что я могу откатить всю транзакцию (запросы, которые выполнялись раньше).

Ответы [ 2 ]

4 голосов
/ 25 июня 2010

Я думаю, что вы могли бы использовать SAVEPOINT перед попыткой выполнить оператор, который может вызвать нарушение. Если нарушение произойдет, вы можете вернуться к SAVEPOINT, но сохранить исходную транзакцию.

Вот еще одна тема, которая может быть полезна: Продолжение транзакции после ошибки нарушения первичного ключа

1 голос
/ 26 июня 2010

Я проголосовал за ответ SAVEPOINT - тем более, что он ссылается на вопрос, где мой ответ был принят. ;)

Однако, учитывая ваше заявление в разделе комментариев о том, что вы ожидаете ошибок "чаще, чем нет", могу ли я предложить другую альтернативу?

Это решение фактически возвращает нас к вашему другому вопросу. Разница здесь в том, как очень быстро загрузить данные в нужное место и отформатировать, чтобы перемещать данные по одному SELECT - и - универсален для любой таблицы, которую вы хотите заполнить (поэтому один и тот же код можно использовать для нескольких разных таблиц ). Вот примерная схема того, как бы я делал это в чистом PostgreSQL, предполагая, что у меня есть CSV-файл в том же формате таблицы, в который нужно вставить:

CREATE TEMP TABLE input_file (LIKE target_table);

COPY input_file FROM '/path/to/file.csv' WITH CSV;

INSERT INTO target_table
SELECT * FROM input_file
WHERE (<unique key field list>) NOT IN (
    SELECT <unique key field list>
    FROM target_table
);

Хорошо, это идеализированный пример, и я также замаскирую несколько вещей (например, отчет о дубликатах, отправка данных в таблицу с помощью данных в памяти Python, копирование из STDIN, а не через файл и т. Д. ), но, надеюсь, основная идея есть, и она позволит избежать значительных накладных расходов, если вы ожидаете, что больше записей будет отклонено, чем принято.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...