如何在 Rails 迁移中将列从整数更改为日期时间?



我有一个名为record_time的列来存储记录的时间 当前列数据类型为整数,数据保存为 UNIX 时间戳 现在我想找到一种方法将此 UNIX 时间戳转换为日期时间字段而不会丢失该列中的数据。 现在我创建了一个迁移文件,如下所示:

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

提前谢谢。

我会完全跳过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调用来更新模型类),但我不明白这一点:更改列类型几乎总是涉及特定于数据库的代码(如果您想提高效率),并且迁移无论如何都是临时桥梁。

在插入 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

相关内容

  • 没有找到相关文章

最新更新