SQLite INSERT - ON DUPLICATE KEY UPDATE (UPSERT)

71

MySQL имеет что-то вроде этого:

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

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

  • SELECT + (INSERT или UPDATE) или
  • UPDATE (+ INSERT, если UPDATE не работает)
Теги:
database
upsert

4 ответа

101
Лучший ответ
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/questions/418898/sqlite-upsert-not-insert-or-replace.

  • 2
    Просто для записи, REPLACE не вариант.
  • 1
    Что касается ссылки «еще одно отличное решение», я также рассмотрю другой ответ на тот же вопрос: stackoverflow.com/a/418988/3650835
16

Я бы предпочел UPDATE (+ INSERT if UPDATE fails). Меньше кода = меньше ошибок.

  • 0
    Спасибо! @Sam ( stackoverflow.com/questions/418898/… ), похоже, согласен с вами. Я тоже предпочитаю такой подход.
  • 1
    @codeholic где я могу получить синтаксис для этого метода
Показать ещё 1 комментарий
4

Текущий ответ будет работать только в sqlite или mysql (в зависимости от того, используете ли вы OR или нет). Итак, если вам нужна совместимость с перекрестными dbms, следующее будет...

REPLACE INTO `visits` (ip, value) VALUES ($ip, 0);
  • 3
    Принятый ответ работает на SQLite (это было моей целью). REPLACE будет работать и на SQLite, но на MySQL он всегда будет сбрасывать счетчик на 0 - пока запрос будет переносимым, конечный результат будет сильно отличаться.
  • 0
    Вы правы, я думал, что ОП ищет что-то портативное. Я понимаю, что REPLACE INTO не будет работать во всех случаях, особенно там, где требуется сохранение PK, но во многих случаях.
Показать ещё 1 комментарий
-1

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

Это быстрее, чем MySQL, и сохраняет нагрузку, поэтому MySQL может сосредоточиться на других вещах.

  • 0
    Если данные не так важны, да. Однако, если это используется на занятом сайте, где много IP-адресов поражают службу, экземпляры memcached могут быть переполнены и привести к удалению некоторого содержимого. Резервное копирование содержимого memcached также будет интересно (если потребуется).
  • 0
    @ElliotFoster Memcached может обрабатывать столько данных, сколько ОЗУ, которое вы к нему добавляете (если вы хотите сохранить данные, тогда используйте redis или membase). Если вы получаете более 1 миллиона посетителей в день, то вы, вероятно, можете позволить себе предоставить вашему экземпляру memcache более 30 МБ ОЗУ (что, по-моему, является значением по умолчанию). Тем не менее, он, безусловно, может справиться с гораздо большей нагрузкой, чем SQLite и MySQL, для объема памяти, который вы ему предоставляете - просто нет никакого сравнения.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню