Към съдържанието
wannacode

UPSERT: вмъкни или обнови

Накратко: Upsert записва нов ред, а ако ред с този ключ вече има, го обновява или го пропуска; в SQLite и PostgreSQL се пише INSERT … ON CONFLICT.

Проблем

Клиентът се връща

Георги Петров се премести в София. Той поръчва, без да влиза в профила си, и формата праща име, имейл и град. Сайтът опитва да го запише като нов клиент:

SQLбаза: магазин

Имейлът му вече е в базата, а той е уникален. Сайтът трябва да реши: нов клиент или стар. Може първо да провери със SELECT и после да избере между INSERT и UPDATE. Но това са две заявки, а между тях друг посетител може да запише същия имейл.

Идеята

ON CONFLICT … DO UPDATE

ON CONFLICT казва на INSERT какво да прави, ако редът нарушава уникална колона. С DO UPDATE обновява реда, който вече е в таблицата:

SQLбаза: магазин

Двата реда минават по различен път. Георги го има: редът му остава с номер 2 и с датата на регистрация от 2025 г., а се сменя само градът. Весела я няма: тя се вмъква като клиент 21.

excluded е редът, който заявката е опитала да вмъкне. excluded.city е градът от VALUES, а city без нищо пред него е старата стойност в таблицата.

Това се казва upsert, от „update“ и „insert“.

По-точно, за любопитните

В PostgreSQL заявката е същата: ON CONFLICT (email) DO UPDATE SET city = EXCLUDED.city. MySQL има свой запис: INSERT … ON DUPLICATE KEY UPDATE. SQL Server и Oracle използват MERGE, по-обща команда, която сравнява две таблици и решава за всеки ред: вмъкни, обнови или изтрий. PostgreSQL има MERGE от версия 15. В SQLite MERGE няма.

Пробвай

Нов адрес

Елена Димитрова (elena.d@example.com) се премести във Варна. Формата праща име, имейл, град Варна и днешната дата 2026-10-25. Запиши я така, че да се смени само градът. Датата на регистрация остава старата.

SQLбаза: магазин

Идеята

Наличности от доставчика

Сутрин пристига доставка: 30 баници, 40 краставици и нов продукт, айрян. Доставчикът ползва номерата на продуктите от магазина, а айрянът вече има номер 26 в каталога. Познатите продукти трябва да получат още бройки, а новият трябва да се появи:

SQLбаза: магазин

Конфликтът е по id, първичния ключ. За баницата и краставиците products.stock + excluded.stock събира старата наличност с доставената. Датата added_at им остава старата, защото не е в SET. Айрянът го няма, затова се вмъква с всичките си колони.

Тук пред stock пише products., защото в израза има две наличности: тази в таблицата и тази от доставката.

Пробвай

Още в количката

Георги добавя 2 пакета масло (продукт 9, 3,20 €) в новата си поръчка 57. Ако го има, количеството трябва да се увеличи, а ако го няма, да се добави ред.

SQLбаза: магазин

Виж го

DO NOTHING

Понякога при конфликт не трябва да се променя нищо. От изложение идва списък с хора, които искат да са клиенти. Който вече е клиент, се пропуска:

SQLбаза: магазин

Мария остава, каквато си беше, с град София. Весела е нов клиент. Без ON CONFLICT цялата заявка щеше да спре на Мария и Весела нямаше да влезе.

По-точно, за любопитните

SQLite има и по-стар, свой запис: INSERT OR IGNORE прави същото като DO NOTHING.

SQLбаза: магазин

INSERT OR REPLACE изглежда като upsert, но не е. При конфликт той изтрива стария ред и вмъква нов. Теодора получава нов номер и нова дата на регистрация:

SQLбаза: магазин

При Георги изтриването изобщо не минава, защото поръчките му сочат към стария ред:

SQLбаза: магазин

Затова за upsert ползвай ON CONFLICT … DO UPDATE. Той сменя само колоните в SET.

Упражнение

Доставката

Доставчикът праща доставката като таблица delivery: номер на продукта, име, категория, цена и количество. За урока таблицата вече е в базата. Пусни началния SELECT, за да я видиш.

Запиши доставката в products. Познатите продукти получават доставеното количество към наличността си и цената от доставчика. Новите се вмъкват с дата 2026-10-25.

Доставката в products:

SQLбаза: магазин

Тест

Провери се

1. Какво е excluded в ON CONFLICT … DO UPDATE?
2. Кога ON CONFLICT (email) влиза в действие?
3. Защо ON CONFLICT (city) не работи в магазина?
4. Каква е разликата между ON CONFLICT DO UPDATE и INSERT OR REPLACE в SQLite?

Създаден от Иво Гергов като част от кампанията на Evo Tech за достъпно обучение по програмиране ·