14

本当に小さなSinatraアプリでSequelを使い始めたところです。DBテーブルが1つしかないので、モデルを使用する必要はありません。

レコードが存在する場合は更新し、存在しない場合は新しいレコードを挿入したい。私は次の解決策を思いついた:

  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]

この方法は、「更新または挿入」動作の最も洗練された実装ではないと思います。

それはどのように行われるべきですか?

4

4 に答える 4

20

更新/挿入する前にチェックしないでください。なぜなら:

  1. これは追加の db 呼び出しです。
  2. これにより、競合状態が発生する可能性があります。

代わりにすべきことは、update の戻り値をテストすることです。

rec = $nums.where(:number => n, :type => t)
if 1 != rec.update(:counter => :counter + 1)
  $nums.insert(:number => n, :counter => 1, :type => t)
end
于 2012-03-28T14:00:43.473 に答える
16

Sequel 4.25.0 (2015 年 7 月 31 日リリース)insert_conflictが Postgres v9.5+ 用に
追加 Sequel 4.30.0 (2016 年 1 月 4 日リリース)insert_conflictが SQLite 用に追加

これは、次のように、行を挿入または更新するために使用できます。

DB[:table_name].insert_conflict(:update).insert( number:n, type:t, counter:c )
于 2016-01-19T22:28:22.037 に答える
3

それよりもきれいにすることはできないと思います(ただし、一部のデータベースには特定の upsert 構文があり、 Sequel でサポートされている可能性があります)。持っているものを別のメソッドにラップして、存在しないふりをすることができます。:)

いくつかの提案:

  • トランザクション内にすべてを囲みます。
  • フィールドに一意のインデックスを作成し(number, type)ます。
  • グローバル変数を使用しないでください。
于 2012-03-19T11:40:44.353 に答える
1

upsertを使用できますが、現在、カウンターの更新には機能しません。うまくいけば、将来のバージョンは-アイデアを歓迎します!

于 2012-07-05T16:14:23.430 に答える