【问题标题】:Rails 4, migration to change datatype of column from daterange to tsrange causing PG::DatatypeMismatch: ERROR:Rails 4,迁移以将列的数据类型从 daterange 更改为 tsrange 导致 PG::DatatypeMismatch: ERROR:
【发布时间】:2013-12-29 00:45:46
【问题描述】:

我正在尝试使用 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

据我所知,USING CAST 主要用于整数。假设我不想删除然后重新创建列,您必须指定什么才能将类型从 daterange 更改为 tsrange?

我正在使用

  • Rails 4.0.1
  • ruby-2.0.0-p247
  • psql (9.2.4)

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

【问题讨论】:

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


    【解决方案1】:

    USING clause 用于指定如何将旧值转换为新值:

    可选的USING 子句指定如何从旧列值计算新列值;如果省略,则默认转换与从旧数据类型到新数据类型的赋值转换相同。如果没有从旧类型到新类型的隐式或赋值强制转换,则必须提供 USING 子句。

    因此,只要没有从旧类型到新类型的默认转换,就会出现 USING。另请注意,USING 被指定为 USING expression,因此任何表达式(其值的类型正确)都可以与 USING 一起使用,最常见的是 USING CAST(...),但 expression 几乎可以是任何东西。

    希望这能消除一些关于使用的困惑。

    那么 ActiveRecord 错误是怎么回事?好吧,change_column 期望在第四个参数中看到 options 哈希,但您发送的是字符串。如果您查看 change_column 源代码,您会看到类似 options[:limit]String#[] 需要整数参数,因此您的字符串参数会触发奇怪的符号抱怨。

    AFAIK 无法让 AR 将 USING 子句添加到 change_column 生成的 ALTER TABLE ... ALTER COLUMN 中。如果您需要 USING 子句,这将留下 connection.execute(some_sql)。当然,由于(显然)缺少从 daterangetsrange 的内置转换,这会更加复杂,但是如果您将 daterangeupper 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 表达式,以查看范围的左右端是打开还是关闭。


    顺便说一句,whenPostgreSQL keyword,因此它不是标识符的最佳选择,每次在 SQL sn-ps 中引用该列时,您都必须说 "when",这可能会得到累。我建议为该列使用不同的名称,这样您就不必担心引用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-09
      • 1970-01-01
      • 1970-01-01
      • 2015-12-28
      • 2018-12-28
      • 2019-07-14
      • 2023-03-27
      • 2016-10-09
      相关资源
      最近更新 更多