我正在尝试使用普通的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主要是为了与int一起使用。假设我不想删除列,然后重新创建列,那么您必须指定什么才能将类型从daterange更改为tsrange?
我正在使用
在下面的PR中,Rails 4引入了一些背景、日期范围和范围:https://github.com/rails/rails/pull/7345。谢谢。
发布于 2013-12-29 09:20:32
USING clause用于指定如何将旧值转换为新值:
可选的
USING
子句指定如何从旧数据类型计算新列值;如果省略,则默认转换与从旧数据类型转换为新数据类型的赋值转换相同。如果没有从旧类型转换为新类型的隐式类型或赋值类型,则必须提供USING
子句。
因此,只要没有从旧类型到新类型的缺省类型转换,就会出现使用。还要注意,USING被指定为USING expression
,因此任何表达式(其值的类型正确)都可以与USING一起使用,最常见的是USING CAST(...)
,但expression
可以是几乎任何东西。
希望这能澄清一些关于使用的困惑。
那么ActiveRecord错误是怎么回事呢?嗯,change_column
期望在第四个参数中看到一个options
散列,但是你发送的是一个字符串。如果你看一下change_column
源代码,你会看到像options[:limit]
这样的东西,但是String#[]
需要整数参数,所以你的字符串参数触发了关于符号的奇怪的抱怨。
没有办法让AR将USING子句添加到change_column
生成的ALTER TABLE ... ALTER COLUMN
中。如果需要USING子句,则只剩下connection.execute(some_sql)
。当然,由于(明显)缺乏从daterange
到tsrange
的内置类型转换,这一点变得更加复杂,但如果使用upper
and lower
函数拆分daterange
,构建必要的表达式并不是很困难:
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表达式,以查看范围的左右两端是开放还是闭合。
顺便说一句,when
是一个PostgreSQL keyword,所以它不是标识符的最佳选择,每次在SQL代码片段中引用该列时,你都必须说"when"
,这可能会很累人。我建议对该列使用不同的名称,这样您就不必担心引用。
https://stackoverflow.com/questions/20820997
复制相似问题