tg-me.com/zen_of_python/4305
Last Update:
Молчаливый «провал» INSERT
Вы запускаете SQL-запрос INSERT
, и вроде всё просто. Нет ошибок. Но и данные не вставлены. Звучит странно? Такое действительно может случиться с PostgreSQL — и случается чаще, чем хотелось бы.
Как можно вставить данные и не вставить одновременно?
Когда INSERT
не срабатывает, первое, что приходит в голову — ошибка. Но PostgreSQL умеет «глотать» такое — ведь вы сами его об этом попросили.
Виновник — ON CONFLICT DO NOTHING
INSERT INTO users (id, email)
VALUES (42, '[email protected]')
ON CONFLICT (id) DO NOTHING;
Здесь мы явно говорим: "если произойдёт конфликт по
id
, ничего не делай". И PostgreSQL по умолчанию так и поступает.Поведение UPSERT при множественных уникальных индекса
Представьте, что в таблице есть не один, а два уникальных индекса:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email TEXT UNIQUE,
username TEXT UNIQUE
);
Теперь вы выполняете:
INSERT INTO users (email, username)
VALUES ('[email protected]', 'johnny');
А если
username = 'johnny'
уже существует, но email
ещё нет?Вставка завершится ошибкой!
Так происходит, потому что
ON CONFLICT
(email)
говорит PostgreSQL: «молчи, если конфликт по email
, но бросай ошибку, если конфликт по чему-то ещё».Чтобы избежать этого, используем:
ON CONFLICT DO NOTHING
Тогда PostgreSQL проигнорирует конфликт по любому индексу. Но это может спровоцировать проблемы, особенно при вставке пачкой
Как отладить такую ситуацию?
— Проверяйте
rowcount
после запроса. В Python/psycopg2, например:
cursor.execute(sql, values)
if cursor.rowcount == 0:
print("Nothing inserted!")
— Добавьте
RETURNING
и логируйте:
INSERT INTO users (email, username)
VALUES ('[email protected]', 'johnny')
ON CONFLICT DO NOTHING
RETURNING id;
Если возвращается пустой результат — значит, вставки не было.
— Логируйте причину. Если вы используете логику вида
DO UPDATE
, можно добавить логи в `UPDATE`-часть или сохранять «причину отказа» отдельно.#sql
BY Zen of Python
Warning: Undefined variable $i in /var/www/tg-me/post.php on line 283
Share with your friend now:
tg-me.com/zen_of_python/4305