2011-03-07 87 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

相關問題