У меня есть сценарий python, использующий executemany для массовой вставки строк в таблицу MySQL. Данные извлекаются из разных API, поэтому время от времени появляются неожиданные данные, которые приводят к строке, вызывающей исключение.
Если я правильно понимаю - при вызове executemany с 1000 строками и одна из них проблематична - весь объем не вставляется.
Я хочу найти способ отправить 1000 записей и успешно загрузить те, которые не вызывают проблем. Так, например, если один из тысячи проблематичен, он не будет загружен, но все остальные 999 будут загружены.
Какая лучшая практика в этом отношении? Я подумываю перехватить исключение и создать запасной вариант, чтобы повторно отправить все 1000 один за другим, но похоже, что должен быть лучший способ достичь того же результата.
Совет?
Если, например, проблематична только запись 364 из партии 1000 - я хотел бы повторить попытку вставки всех остальных 999 записей по отдельности. Поскольку я не знаю, какая запись вызвала исключение, а потому, что одно исключение вызывает сбой всего пакета, я думаю о повторении всех 1000 как отдельных операторов (выполнить вместо выполнения многих). Исключением может быть что угодно: пустое поле PK, неожиданная кодировка и т. д.
да, повторная попытка сузит ошибку до минимального количества строк.
При вставке executemany
объединяет все строки данных вместе и пытается вставить их все одной командой. Насколько мне известно, невозможно обработать исключение, вызванное одной неудачной вставкой, без разрушения всего пакета вставок. Если одна строка терпит неудачу, вся команда терпит неудачу.
Вот как это выглядит (пример взят из Документы MySQL). Если вы скажете ему сделать это:
data = [
('Jane', date(2005, 2, 12)),
('Joe', date(2006, 5, 23)),
('John', date(2010, 10, 3)),
]
stmt = "INSERT INTO employees (first_name, hire_date) VALUES (%s, %s)"
cursor.executemany(stmt, data)
executemany
сделает это:
INSERT INTO employees (first_name, hire_date)
VALUES ('Jane', '2005-02-12'), ('Joe', '2006-05-23'), ('John', '2010-10-03')
Если вы думаете, что это будет редкостью, ваша идея повторять попытки каждой вставки по отдельности сработает. Что-то типа:
try:
cursor.executemany(stmt, data)
except ___Error: # fill in the blank
for datum in data:
try:
cursor.execute(stmt, datum)
except ___Error:
# handle exception, eg print warning
...
Если вы думаете, что это будет частая проблема, то, вероятно, будет эффективнее отказаться от executemany
и просто сделать следующее:
for datum in data:
try:
cursor.execute(stmt, datum)
except ___Error:
# handle exception, eg print warning
...
Выполнение инструкции «INSERT OR IGNORE» в начале вашего запроса «executemany» позволит вам сделать именно это - он добавит только те значения, которые не приводят к ошибке.
Единственным недостатком является то, что вы больше не можете видеть, какая ошибка происходит. Например,
Исходная база данных:
('kaushik', 3)
('maria', 4)
('shreya', 38)
Запрос: (в Python)
listofnames = [
('kaushik', 3),
('maria', 4),
('jane', 56)
]
c.executemany("INSERT OR IGNORE INTO bob (name, number) VALUES (?,?)",
listofnames)
Окончательный db:
('kaushik', 3)
('maria', 4)
('shreya', 38)
('jane', 56)
какие исключения вы получаете? Что заставляет вас думать, что повторная попытка сработает?