在Rails迁移中将一列更新为另一列的值

时间:2011-03-07 20:30:42

标签: ruby-on-rails activerecord migration timestamp

我在Rails应用程序中有一个包含数十万条记录的表,它们只有created_at个时间戳。我正在添加编辑这些记录的功能,因此我想在表中添加updated_at时间戳。在我添加列的迁移中,我想更新所有行以使新updated_at与旧created_at匹配,因为这是Rails中新创建的行的默认值。我可以做一个find(:all)并遍历记录,但由于表的大小,这需要几个小时。我真正想做的是:

UPDATE table_name SET updated_at = created_at;

在使用ActiveRecord进行Rails迁移而不是执行原始SQL时,有没有更好的方法呢?

8 个答案:

答案 0 :(得分:112)

我会创建一个迁移

rails g migration set_updated_at_values

并在里面写下类似的内容:

class SetUpdatedAt < ActiveRecord::Migration
  def self.up
    Yourmodel.update_all("updated_at=created_at")
  end

  def self.down
  end
end

这样你就可以实现两件事

  • 这是一个可重复的过程,每次可能的部署(如果需要)都会执行
  • 这很有效。我想不出更多的rubyesque解决方案(效率很高)。

注意:如果查询太难以使用activerecord写入,您也可以在迁移中运行原始sql。请写下以下内容:

Yourmodel.connection.execute("update your_models set ... <complicated query> ...")

答案 1 :(得分:20)

您可以使用与原始SQL非常相似的update_all。这就是你拥有的所有选择。

BTW个人而言,我并不太关注迁移。有时原始SQL是最好的解决方案。通常,迁移代码不会被重用。这是一次性操作,所以我不打扰代码纯度。

答案 2 :(得分:10)

正如gregdan所写,你可以使用update_all。你可以这样做:

Model.where(...).update_all('updated_at = created_at')

第一部分是您的典型条件。最后一部分说明了如何进行分配。这将产生UPDATE语句,至少在Rails 4中。

答案 3 :(得分:0)

这是一种通用的解决方法,无需编写查询,因为查询会面临风险。

  class Demo < ActiveRecord::Migration
    def change
     add_column :events, :time_zone, :string
     Test.all.each do |p|
       p.update_attributes(time_zone: p.check.last.time_zone)
     end
     remove_column :sessions, :time_zone
    end
  end

答案 4 :(得分:0)

您可以直接对您的rails console运行以下命令 ActiveRecord::Base.connection.execute("UPDATE TABLE_NAME SET COL2 = COL1")

例如:我想用项目表的remote_id更新项目表的sku。该命令将如下所示:
ActiveRecord::Base.connection.execute("UPDATE items SET sku = remote_id")

答案 5 :(得分:0)

不要在迁移中使用应用程序模型,除非您在迁移中重新定义它们。如果您使用应用程序模型,您以后更改或删除迁移可能会失败。

当然,您也可以在迁移中使用 SQL 的全部功能。

阅读https://makandracards.com/makandra/15575-how-to-write-complex-migrations-in-rails

答案 6 :(得分:0)

您还可以添加 updated_at 列并在一次迁移中更新其值:

class AddUpdatedAtToTableName < ActiveRecord::Migration
  def change
    add_column :table_name, :updated_at, :datetime

    reversible do |dir|
      dir.up do
        update "UPDATE table_name SET updated_at=created_at"
      end
    end
  end
end

答案 7 :(得分:-3)

作为一次性操作,我只会在rails console中执行此操作。真的需要几个小时吗?也许如果有数百万条记录......

records = ModelName.all; records do |r|; r.update_attributes(:updated_at => r.created_at); r.save!; end;`