ВСТАВЛЕННЯ SQLite - ПОВТОРЕННЯ КЛЮЧОВОГО ОНОВЛЕННЯ (UPSERT)


98

MySQL має щось подібне:

INSERT INTO visits (ip, hits)
VALUES ('127.0.0.1', 1)
ON DUPLICATE KEY UPDATE hits = hits + 1;

Наскільки я знаю, ця функція не існує в SQLite, я хочу знати, чи є якийсь спосіб отримати той самий ефект без необхідності виконувати два запити. Крім того, якщо це неможливо, що ви віддаєте перевагу:

  1. SELECT + (ВСТАВИТИ або ОНОВИТИ) або
  2. UPDATE (+ INSERT, якщо UPDATE не вдається )

Відповіді:


31

Оскільки 3.24.0 SQLite також підтримує upsert , тож тепер ви можете просто написати наступне

INSERT INTO visits (ip, hits)
VALUES ('127.0.0.1', 1)
ON CONFLICT(ip) DO UPDATE SET hits = hits + 1;

3
Мені цікаво, чи можна зробити кілька upsertподібних дій в одній транзакції, тобто за допомогою executemany()функції Python ?
Радіокерований

117
INSERT OR IGNORE INTO visits VALUES ($ip, 0);
UPDATE visits SET hits = hits + 1 WHERE ip LIKE $ip;

Для цього потрібно, щоб у стовпці "ip" було обмеження UNIQUE (або PRIMARY KEY).


EDIT: Ще одне чудове рішення: https://stackoverflow.com/a/4330694/89771 .


2
Просто для запису, REPLACEце не варіант.
Алікс Аксель

1
Що стосується «іншої відмінного рішення» посилання, я б також розглянути іншу відповідь на те ж питання: stackoverflow.com/a/418988/3650835
KayakinKoder

19

Я б віддав перевагу UPDATE (+ INSERT if UPDATE fails). Менше коду = менше помилок.


1
Дякую! @ Сем ( stackoverflow.com/questions/418898 / ... ) , схоже, згоден з вами. Я також віддаю перевагу такому підходу.
Алікс Аксель

@Smith я мав на увазі використання простих операторів UPDATE та INSERT та перевірку поверненого значення.
кодеголік

Це не має атомності, можливо, INSERT зазнає невдачі, якщо якийсь інший процес, вставлений між ними.
Робін Лавалле,

7

Поточна відповідь працюватиме лише в sqlite АБО mysql (залежно від того, використовуєте ви АБО чи ні). Отже, якщо ви хочете перехресну сумісність із DBMS, буде виконуватися наступне ...

REPLACE INTO `visits` (ip, value) VALUES ($ip, 0);

3
Прийнята відповідь працює на SQLite (це була моя мета). REPLACEбуде працювати і на SQLite, але на MySQL він завжди скидає лічильник на 0 - хоча запит буде портативним, кінцевий результат буде сильно відрізнятися.
Алікс Аксель

Ви маєте рацію, я думав, що ОП шукає щось портативне. Я усвідомлюю, що REPLACE INTO працюватиме не з усіма випадками, особливо там, де необхідне збереження ПК, але для багатьох випадків буде.
Jacob Thomason

Помилка, замість того, щоб відкинути дані - це особливість, а не помилка.
Тобу

-4

Для цього слід використовувати memcached, оскільки це єдиний ключ (IP-адреса), що зберігає одне значення (кількість відвідувань). Ви можете використовувати функцію атомного приросту, щоб переконатися у відсутності умов "перегонів".

Це швидше, ніж MySQL, і економить навантаження, тому MySQL може зосередитись на інших речах.


Якщо дані не так важливі, так. Однак, якщо це використовується на зайнятому сайті, де багато IP-адрес потрапляють на службу, екземпляри memcached можуть заповнитись і призвести до видалення деякого вмісту. Резервне копіювання записаного вмісту також було б цікавим (якщо потрібно.)
Елліот Фостер,

@ElliotFoster Memcached може обробляти стільки даних, скільки оперативної пам'яті, яку ви в неї вкидаєте (якщо ви хочете постійності, тоді використовуйте redis або membase). Якщо ви отримуєте більше 1 мільйона відвідувачів на день, тоді ви, мабуть, можете собі дозволити надавати своєму екземпляру memcache більше 30 МБ оперативної пам'яті (що, за замовчуванням, я думаю). Однак він, безсумнівно, може витримати набагато більше навантаження, ніж SQLite та MySQL, за об'ємом пам'яті, яку ви йому надаєте - просто немає порівняння.
Xeoncross

Будь ласка, не сприймайте мій коментар як голосування проти memcache, оскільки я вважаю це фантастичним інструментом. Як і redis (я не можу говорити за membase, оскільки я ним не користувався.) Однак memcache / redis - не найнадійніші магазини. Так, redis має стійкість, але дані зберігаються на диску через певний проміжок часу (останній раз я дивився), а memcache - зовсім не. Як я вже сказав, якщо дані не важливі (або їх можна легко відтворити), тоді memcache та компанія чудові. Оригінальна публікація також запитувала про sqlite, який дуже відрізняється від MySQL і, ймовірно, означає, що вони обмежені іншими способами.
Елліот Фостер,

Ви можете налаштувати Redis на збереження даних так швидко, як завгодно (при X кількості секунд або при Y кількості змін).
Буффало
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.