如何在Sequel数据集上更新或插入?

时间:2012-03-19 11:06:30

标签: ruby upsert sequel

我刚开始在一个非常小的Sinatra应用程序中使用Sequel。由于我只有一个数据库表,所以我不需要使用模型。

我想更新记录(如果存在)或插入新记录(如果不存在)。我提出了以下解决方案:

  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

$numsDB[:numbers]数据集的位置。

我认为这种方式不是“更新或插入”行为的最优雅实现。

应该怎么做?

4 个答案:

答案 0 :(得分:17)

在更新/插入之前,您可能不应该检查;这是因为:

  1. 这是一个额外的数据库调用。
  2. 这可能会引入竞争条件。
  3. 您应该做的是测试更新的返回值:

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

答案 1 :(得分:10)

续集4.25。0(2015年7月31日发布)增加了insert_conflict for Postgres v9.5+
续集4.30.0(2016年1月4日发布)增加了insert_conflict for SQLite

这可用于插入或更新行,如下所示:

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

答案 2 :(得分:3)

我相信你不能比它更清洁(虽然有些数据库有特定的upsert语法,可能是supported by Sequel)。您可以在单独的方法中包装您拥有的内容并假装它不存在。 :)

只是几点建议:

  • 将所有内容都包含在交易中。
  • (number, type)字段上创建唯一索引。
  • 不要使用全局变量。

答案 3 :(得分:1)

您可以使用upsert,但目前无法更新计数器。希望未来的版本会 - 欢迎提出想法!