我正在尝试使用vanilla Rails迁移将daterange类型的列更改为tsrange(我意识到我需要时间和日期)
def self.up
change_column :events, :when, :tsrange
end
运行rake db:migrate
后错误是
PG::DatatypeMismatch: ERROR: column "when" cannot be cast automatically to type tsrange
HINT: Specify a USING expression to perform the conversion.
: ALTER TABLE "events" ALTER COLUMN "when" TYPE tsrange
我尝试了以下提示并使用了以下
def self.up
change_column :events, :when, :tsrange, 'tsrange USING CAST(when AS tsrange)'
end
但后来
no implicit conversion of Symbol into Integer
据我所知,使用CAST主要用于整数。假设我不想删除然后重新创建列,你必须指定什么来改变从daterange到tsrange的类型?
我正在使用
在以下PR中向Rails 4引入了一些背景,日期范围和tsrange:https://github.com/rails/rails/pull/7345。感谢。
答案 0 :(得分:3)
USING clause用于指定如何将旧值转换为新值:
可选的
USING
子句指定如何从旧的计算新列值;如果省略,则默认转换与从旧数据类型转换为new的赋值相同。如果没有从旧类型到新类型的隐式或赋值转换,则必须提供USING
子句。
因此,只要没有从旧类型到新类型的默认转换,USING就会显示出来。另请注意,USING指定为USING expression
,因此任何表达式(其值都是正确的类型)都可以与USING一起使用,最常见的是USING CAST(...)
,但expression
可以很漂亮什么都有。
希望这可以解决一些关于使用的混淆。
那么ActiveRecord错误是怎么回事?好吧,change_column
期望在第四个参数中看到options
哈希,但是你发送了一个字符串。如果您查看change_column
来源,您会看到options[:limit]
之类的内容,但String#[]
需要整数参数,因此您的字符串参数会引发奇怪的关于符号的抱怨。
AFAIK无法让AR在ALTER TABLE ... ALTER COLUMN
生成的change_column
中添加USING子句。如果您需要USING子句,则会留下connection.execute(some_sql)
。当然,从daterange
到tsrange
的(明显的)内置演员阵容的缺乏使得这一点变得更加复杂,但是如果你将daterange
分开,建立必要的表达并不是非常困难使用upper
and lower
函数:
connection.execute(%q{
alter table events
alter column "when"
type tsrange using tsrange(lower("when"), upper("when"))
})
您可以在此处查看表格更改:http://sqlfiddle.com/#!15/fb047/2
假设您使用默认的半开间隔([...)
)作为范围;如果您的范围在左侧未关闭且在右侧打开,则您必须使用other range functions构建更复杂的USING表达式,以查看范围的左端和右端是否已打开或闭合。
BTW,when
是PostgreSQL keyword因此它不是标识符的最佳选择,每次在SQL片段中引用该列时,您都必须说"when"
这可能会让人感到疲惫。我建议为该列使用不同的名称,这样您就不必担心引用了。