Как обновить или вставить в пакет данных 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]
.
Я считаю, что этот способ - не самая элегантная реализация поведения "обновление или вставка".
Как это сделать?
Ответы
Ответ 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, за исключением того, что в настоящее время он не работает для обновления счетчиков. Надеемся, что будущая версия - идеи приветствуются!