Rails:如何增加模型的选定实例的整数字段?

时间:2011-01-15 04:47:28

标签: ruby-on-rails ruby-on-rails-3

Buyer模型有两个字段:

  • name(string)
  • 位置(整数)

我想增加position

的所有买家的position >= N

最简单的方法是什么?

是否可以仅使用一个查询来实现此目的?

3 个答案:

答案 0 :(得分:17)

您可以使用:

Buyer.update_all("position = position + 1", ["position >= ?", n])

如果n = 25:

,这将生成查询
UPDATE "buyers" SET position = position + 1 WHERE (position >= 25)

编辑:

由于您拥有UNIQUE数据库约束,因此您有两个选项。对于这两个选项,我建议在事务中运行它们。首先,您可以按相反的顺序单独更新每个字段,但这将导致您有N + 1个查询。对于小型数据集,这不会是一个问题,但对于较大的数据集,这可能会影响性能。

Buyer.transaction do
   Buyer.select("id, position").where(["position >= ?", n]).order("position DESC").each do |buyer|
      buyer.position += 1
      buyer.save
   end
end

另一个选项,即避免N + 1个查询,是将位置增量更改为100(或10)。这将允许您更新两个查询中的位置,而不是N + 1。因此,不是拥有位置1,2,3等,而是拥有100,200,300等。然后要进行更新,您将所有值增加101,然后按照更新进行更新以减去1。

Buyer.transaction do
   Buyer.where(["position >= ?", n]).scoping do
      Buyer.update_all("position = position + 101")
      Buyer.update_all("position = position - 1")
   end
end

答案 1 :(得分:1)

如果这是临时的,您可以删除约束/索引,运行更新,然后使用常规旧SQL重新添加它。

答案 2 :(得分:-1)

class Buyer < ActiveRecord::Base
  scope :positioned_at_or_above, lambda {|pos| where("position >= ?", pos) }

  def self.increment(amount, position_threshold)
    Buyer.positioned_at_or_above(position_threshold).each{|buyer| buyer.update_attributes(:position => buyer.position + amount)}
  end
end

-

increment ∴ rails c                                                                                                                                                               
Loading development environment (Rails 3.0.3)
>> Buyer.count
=> 0
>> (1..10).each {|idx| Buyer.create(:name => "Buyer ##{idx}", :position => idx)}
=> 1..10
>> pp Buyer.all
[#<Buyer id: 11, name: "Buyer #1", position: 1>,
 #<Buyer id: 12, name: "Buyer #2", position: 2>,
 #<Buyer id: 13, name: "Buyer #3", position: 3>,
 #<Buyer id: 14, name: "Buyer #4", position: 4>,
 #<Buyer id: 15, name: "Buyer #5", position: 5>,
 #<Buyer id: 16, name: "Buyer #6", position: 6>,
 #<Buyer id: 17, name: "Buyer #7", position: 7>,
 #<Buyer id: 18, name: "Buyer #8", position: 8>,
 #<Buyer id: 19, name: "Buyer #9", position: 9>,
 #<Buyer id: 20, name: "Buyer #10", position: 10>]
=> nil
>> pp Buyer.positioned_at_or_above(4)
[#<Buyer id: 14, name: "Buyer #4", position: 4>, #<Buyer id: 15, name: "Buyer #5", position: 5>, #<Buyer id: 16, name: "Buyer #6", position: 6>, #<Buyer id: 17, name: "Buyer #7", position: 7>, #<Buyer id: 18, name: "Buyer #8", position: 8>, #<Buyer id: 19, name: "Buyer #9", position: 9>, #<Buyer id: 20, name: "Buyer #10", position: 10>]
=> nil
>> pp Buyer.positioned_at_or_above(4).all
[#<Buyer id: 14, name: "Buyer #4", position: 4>,
 #<Buyer id: 15, name: "Buyer #5", position: 5>,
 #<Buyer id: 16, name: "Buyer #6", position: 6>,
 #<Buyer id: 17, name: "Buyer #7", position: 7>,
 #<Buyer id: 18, name: "Buyer #8", position: 8>,
 #<Buyer id: 19, name: "Buyer #9", position: 9>,
 #<Buyer id: 20, name: "Buyer #10", position: 10>]
=> nil
>> Buyer.increment(1000, 4)
=> [#<Buyer id: 14, name: "Buyer #4", position: 1004>, #<Buyer id: 15, name: "Buyer #5", position: 1005>, #<Buyer id: 16, name: "Buyer #6", position: 1006>, #<Buyer id: 17, name: "Buyer #7", position: 1007>, #<Buyer id: 18, name: "Buyer #8", position: 1008>, #<Buyer id: 19, name: "Buyer #9", position: 1009>, #<Buyer id: 20, name: "Buyer #10", position: 1010>]
>> pp Buyer.all
[#<Buyer id: 11, name: "Buyer #1", position: 1>,
 #<Buyer id: 12, name: "Buyer #2", position: 2>,
 #<Buyer id: 13, name: "Buyer #3", position: 3>,
 #<Buyer id: 14, name: "Buyer #4", position: 1004>,
 #<Buyer id: 15, name: "Buyer #5", position: 1005>,
 #<Buyer id: 16, name: "Buyer #6", position: 1006>,
 #<Buyer id: 17, name: "Buyer #7", position: 1007>,
 #<Buyer id: 18, name: "Buyer #8", position: 1008>,
 #<Buyer id: 19, name: "Buyer #9", position: 1009>,
 #<Buyer id: 20, name: "Buyer #10", position: 1010>]
=> nil
>>