Rails 4,迁移到将列的数据类型从daterange更改为tsrange导致PG :: DatatypeMismatch:错误:

时间:2013-12-29 00:45:46

标签: postgresql activerecord ruby-on-rails-4 range postgresql-9.2

我正在尝试使用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的类型?

我正在使用

  • Rails 4.0.1
  • 红宝石2.0.0-P247
  • psql(9.2.4)

在以下PR中向Rails 4引入了一些背景,日期范围和tsrange:https://github.com/rails/rails/pull/7345。感谢。

1 个答案:

答案 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)。当然,从daterangetsrange的(明显的)内置演员阵容的缺乏使得这一点变得更加复杂,但是如果你将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,whenPostgreSQL keyword因此它不是标识符的最佳选择,每次在SQL片段中引用该列时,您都必须说"when"这可能会让人感到疲惫。我建议为该列使用不同的名称,这样您就不必担心引用了。