2017-05-11 86 views
-1

我有一個名爲record_time的列來存儲記錄的時間,目前列數據類型是整數,數據保存爲unix時間戳,現在我想找到一種方法將此unix時間戳轉換爲datetime字段,而不會丟失該列中的數據。現在,我已經創建了一個遷移文件,如下所示:如何在Rails遷移中將整數列更改爲datetime?

class ChangeRecordTimeToDatetime < ActiveRecord::Migration 
    def up 
    as = Audio.all.map {|a| {id: a.id, record_time: Time.at(a.record_time)}} 
    Audio.all.update_all("record_time = NULL") 
    change_column :audios, :record_time, :datetime 
    as.map {|a| Audio.find(a[:id]).update(record_time: a[:record_time])} 
    end 

    def down 
    as = Audio.all.map {|a| {id: a.id, record_time: a.record_time.to_i}} 
    Audio.all.update_all("record_time = NULL") 
    change_column :audios, :record_time, :integer 
    as.map {|a| Audio.find(a[:id]).update(record_time: a[:record_time])} 
    end 
end 

,這引發了我的錯誤,如提前這個

Mysql2::Error: Incorrect datetime value: '1493178889' for column 'record_time' at row 1: ALTER TABLE `audios` CHANGE `record_time` `record_time` datetime DEFAULT NULL 

感謝。

+1

在插入之前,您需要將UNIX時間戳轉換爲DateTime對象。你可以這樣做:'DateTime.strptime(「1493178889」,'%s')' –

+0

謝謝,目前我正在使用'Time.at(1493178889)'DateTime.strptime(「1493178889 「,'%s')''和'Time.at(1493178889)'只是爲了更清楚。 –

+1

'DateTime.strptime'返回一個'DateTime'對象。 'Time.at'返回一個'時間'。由於您的專欄是'DATETIME',因此您可能會希望在可能的情況下使用Ruby'DateTime'。 –

回答

1

在插入它們之前,需要將UNIX時間戳轉換爲DateTime對象。你可以這樣做:DateTime.strptime(<timestamp>,'%s')

所以將其應用到你的問題,試試這個:

def up 
    as = Audio.all.map {|a| {id: a.id, record_time: DateTime.strptime(a.record_time.to_s, '%s')}} 
    remove_column :audios, :record_time 
    add_column :audios, :record_time, :datetime 
    as.map {|a| Audio.find(a[:id]).update(record_time: a[:record_time])} 
    end 
+0

這會引發同樣的錯誤。 –

3

我會跳過的ActiveRecord完全爲這樣的事情而做這一切的數據庫中。有些數據庫將指定如何在更改列的類型時將舊值轉換爲新值,但我不明白如何使用MySQL來完成此操作;相反,您可以手動完成:

  1. 添加一個新數據類型的新列。
  2. 在轉換日期類型時,執行單個UPDATE將舊值複製到新列。你可以使用MySQL的from_unixtime
  3. 刪除原始列。
  4. 將新列重新命名爲舊名稱。
  5. 重建您在原始列上的任何索引。

翻譯,要遷移:

def up 
    connection.execute(%q{ 
    alter table audios 
    add record_time_tmp datetime 
    }) 
    connection.execute(%q{ 
    update audios 
    set record_time_tmp = from_unixtime(record_time) 
    }) 
    connection.execute(%q{ 
    alter table audios 
    drop column record_time 
    }) 
    connection.execute(%q{ 
    alter table audios 
    change record_time_tmp record_time datetime 
    }) 
    # Add indexes and what not... 
end 

你順利進入數據庫特定的代碼在這裏直SQL那麼回事似乎是合理的我。您當然可以將其轉換爲change_columnupdate_all調用(可能調用reset_column_information調用來更新模型類),但我沒有看到重點:更改列類型幾乎總是會涉及特定於數據庫的代碼(如果您希望高效)和遷移無論如何都是臨時橋樑。