我有一个名为record_time
的列来存储记录的时间,当前列数据类型是整数,数据保存为unix时间戳现在我想找到一种方法将此unix时间戳转换为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
提前致谢。
答案 0 :(得分:3)
我完全跳过ActiveRecord来处理这类事情并在数据库中完成所有操作。一些数据库将指定如何在更改列的类型时将旧值转换为新值但我不知道如何使用MySQL执行此操作;相反,你可以手工完成:
from_unixtime
来实现此目的。将其转换为迁移:
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_column
和update_all
调用(可能使用reset_column_information
调用来更新模型类)但我没有看到重点:更改列类型几乎总是如此涉及特定于数据库的代码(如果你想要高效),并且迁移本来就是临时桥梁。
答案 1 :(得分:2)
在插入之前,需要将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