Rails: Как увеличить целочисленное поле выбранных экземпляров модели? - PullRequest
9 голосов
/ 15 января 2011

Buyer модель имеет два поля:

  • имя (строка)
  • позиция (целое число)

Я хочу увеличить position всех покупателей, чей position >= N.

Какой самый простой способ сделать это?

Можно ли добиться этого, используя только один запрос?

Ответы [ 3 ]

17 голосов
/ 15 января 2011

Вы можете использовать:

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

Это сгенерирует запрос, если n = 25:

UPDATE "buyers" SET position = position + 1 WHERE (position >= 25)

Edit:

Поскольку у вас есть уникальные ограничения базы данных, у вас есть несколько вариантов. Для обоих вариантов я рекомендую запустить их в транзакции. Во-первых, вы можете обновить каждое поле отдельно в обратном порядке, но это приведет к тому, что у вас будет 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 голос
/ 30 ноября 2011

Если это ad-hoc, вы можете удалить ограничение / индекс, запустить обновление, а затем повторно добавить его, используя обычный старый SQL.

0 голосов
/ 15 января 2011
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
>> 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...