如何使用 Rails 将 PostgreSQL 中的时间列更改为整数列?

How do I change a time column to an integer column in PostgreSQL with Rails?

我在连接到新 Rails 应用程序的 PostgreSQL 数据库中的 table 中有一个名为 duration 的列,名为 time_entries。它目前被格式化为时间数据,但我希望它是一个整数。 (具体来说,我打算使用 smallint 专栏,因为它的分钟数不会超过一天,即 1440。)

首先,我试过:

change_column :time_entries, :duration, :smallint, limit: 2

但是我得到以下错误:

PG::DatatypeMismatch: ERROR:  column "duration" cannot be cast automatically to type smallint
HINT:  You might need to specify "USING duration::smallint".

然后,在查看 this post and this post 之后,我尝试了以下迁移:

change_column :time_entries, :duration, 'integer USING CAST(duration AS integer)'
change_column :time_entries, :duration, :smallint, limit: 2

但第一行返回以下错误:

PG::CannotCoerce: ERROR:  cannot cast type time without time zone to integer

如何转换?时区无关紧要,因为它实际上表示持续时间。我是 Rails 新手,对原始 SQL 代码一无所知。谢谢!

您需要提供一个表达式来使用 USING 子句进行实际转换:

ALTER TABLE time_entries ALTER duration TYPE int2 USING EXTRACT(EPOCH FROM duration)::int2;

请注意,任何超出 smallint 范围的值都会引发异常,从而中止整个事务。

dbfiddle here

相关:

  • Rails Migrations: tried to change the type of column from string to integer
  • Get a timestamp from concatenating day and time columns

您可以很容易地从 TIME 值中提取纪元(秒数):

SELECT EXTRACT(EPOCH FROM '01:00:00'::TIME)::INT
-- Returns 3600 

对于你的情况,我怀疑你可以这样做:

change_column :time_entries, :duration, 'integer USING EXTRACT(EPOCH FROM duration)::INT'

感谢其他答案中提供的信息,我在 Rails 迁移中执行了以下操作:

change_column :time_entries, :duration, 'SMALLINT USING EXTRACT(EPOCH FROM duration)/60::SMALLINT'

这将列转换为代表分钟数的 SMALLINT 数字。我只是想在这里包含最终解决方案,因为我稍微修改了其他答案的代码。