Подтвердить что ты не робот

Как обновить или вставить в пакет данных Sequel?

Я только начал использовать Sequel в действительно маленьком приложении Sinatra. Поскольку у меня есть только одна таблица БД, мне не нужно использовать модели.

Я хочу обновить запись, если она существует, или вставить новую запись, если это не так. Я придумал следующее решение:

  rec = $nums.where(:number => n, :type => t)
  if $nums.select(1).where(rec.exists)
    rec.update(:counter => :counter + 1)
  else
    $nums.insert(:number => n, :counter => 1, :type => t)
  end

Где $nums - это набор данных DB[:numbers].

Я считаю, что этот способ - не самая элегантная реализация поведения "обновление или вставка".

Как это сделать?

4b9b3361

Ответ 1

Вероятно, вы не должны проверять перед обновлением/вставкой; потому что:

  • Это дополнительный вызов db.
  • Это может привести к состоянию гонки.

Вместо этого вы должны проверить возвращаемое значение обновления:

rec = $nums.where(:number => n, :type => t)
if 1 != rec.update(:counter => :counter + 1)
  $nums.insert(:number => n, :counter => 1, :type => t)
end

Ответ 2

Sequel 4.25.0 (выпущен 31 июля 2015 г.) добавлен insert_conflict для Postgres v9.5 +
Sequel 4.30.0 (выпущен 4 января 2016 г.) добавил insert_conflict для SQLite

Это можно использовать для вставки или обновления строки, например:

DB[:table_name].insert_conflict(:update).insert( number:n, type:t, counter:c )

Ответ 3

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

Только пара предложений:

  • Включение всей транзакции.
  • Создайте уникальный индекс в полях (number, type).
  • Не используйте глобальные переменные.

Ответ 4

Вы можете использовать upsert, за исключением того, что в настоящее время он не работает для обновления счетчиков. Надеемся, что будущая версия - идеи приветствуются!