2011-03-07 41 views
56

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

UPDATE table_name SET updated_at = created_at; 

有没有更好的方式来做到这一点在使用ActiveRecord,而不是执行原始的SQL一个Rails迁移?

回答

80

我将创建一个迁移

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> ...") 
+0

+1 - 我最近不得不这样做,并通过ActiveRecord使用SQL。它的速度尽可能快。 – 2011-03-08 01:04:23

+38

'Yourmodel.update_all'update_at = created_at''更好,不是吗?它也适用于范围。 – 2013-05-29 20:05:34

19

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

顺便说一句,我个人不会太在意迁移。有时候,原始SQL是最好的解决方案。通常,迁移代码不会被重复使用。这是一次性操作,所以我不打扰代码的纯度。

+1

这取决于您的部署需求。我非常喜欢使用迁移,因为它们允许在现有平台上重复部署并获得相同的结果。我们有几个部署阶段:开发,测试,qa /验收,概念验证平台(用于测试客户端),生产平台:我们需要能够将现有数据迁移到新部署的版本,而不会出现错误。添加一列并确保数据正常在我们的案例中不是一次性操作。 – nathanvda 2011-03-07 21:35:16

+0

我写关于在迁移文件中使用'update_all' :-)你也可以在迁移文件中执行原始SQL。然而'update_all'稍微优雅一点。两者的表现完全相同。 – 2011-03-07 21:47:16

+0

在迁移中声明模型通常是一个聪明的想法,因为如果稍后重新定义原始模型,这将防止出现问题。刚刚发现这篇文章,它很好地解释了一切:http://complicated-simplicity.com/2010/05/using-models-in-rails-migrations/ – 2011-03-08 03:20:47

-2

作为一次性手术,我只是在rails console。它真的需要几个小时吗?也许,如果有几百万的记录...

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

这实际上是我首先尝试的,但因为有成千上万的记录需要更改,所以需要几个小时(几天?)。 – jrdioko 2011-03-07 20:43:13

+0

当我测试它时,它在我的开发人员机器(不是服务器)上每秒钟发生约50条记录。 – jrdioko 2011-03-07 22:12:16

+3

如果可能,总是避免迭代,避免使用'all'将每条记录一次加载到RAM中,并且由于update_attributes已经自动保存,所以需要额外的保存!将使整个行动需要两倍的时间。 – ryan0 2015-03-10 19:55:12

4

由于gregdan写道,你可以使用update_all。你可以这样做:

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

第一部分是你典型的一组条件。最后一部分说明如何完成作业。这将产生一个UPDATE声明,至少在Rails 4中。

+0

这在4.2中生成'SET'posts'。'email'='options'',选项是一个字符串 – lulalala 2015-10-06 13:21:10

+0

确认这个提示对我也不适用。不确定这是完全错误的解决方案。不要donwvote @martin回答 – woto 2015-10-16 18:31:16

+0

下面是Rails控制台的输出:'User.update_all('updated_at = created_at')''SQL(0.4ms)UPDATE“users”SET updated_at = created_at' – 2015-10-17 14:09:38

相关问题