Как обрабатывать исключение с помощью executemany (MySQL и Python)

У меня есть сценарий python, использующий executemany для массовой вставки строк в таблицу MySQL. Данные извлекаются из разных API, поэтому время от времени появляются неожиданные данные, которые приводят к строке, вызывающей исключение.

Если я правильно понимаю - при вызове executemany с 1000 строками и одна из них проблематична - весь объем не вставляется.

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

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

Совет?

какие исключения вы получаете? Что заставляет вас думать, что повторная попытка сработает?

danblack 04.12.2018 02:37

Если, например, проблематична только запись 364 из партии 1000 - я хотел бы повторить попытку вставки всех остальных 999 записей по отдельности. Поскольку я не знаю, какая запись вызвала исключение, а потому, что одно исключение вызывает сбой всего пакета, я думаю о повторении всех 1000 как отдельных операторов (выполнить вместо выполнения многих). Исключением может быть что угодно: пустое поле PK, неожиданная кодировка и т. д.

Aamit 04.12.2018 03:33

да, повторная попытка сузит ошибку до минимального количества строк.

danblack 04.12.2018 03:39
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
3
1 952
2

Ответы 2

При вставке 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)

Другие вопросы по теме