【问题标题】:Postgres: Default for column (string) cannot be cast automatically to type enumPostgres:列(字符串)的默认值不能自动转换为枚举类型
【发布时间】:2015-10-12 14:12:43
【问题描述】:

我想成为一个枚举表中有一个status 列。最初我将该字段创建为整数,认为我会使用内置的 Rails 枚举功能。事实证明这至少需要 Rails 4.1,但我使用的是 4.0,升级过程需要一些时间。

但考虑到这一切是如何运作的,我意识到我可以拥有要么 ActiveRecord 枚举 postgres 枚举,而不是两者兼有。我认为从长远来看,最好有一个更明确的 postgres 枚举。因此,我编写了一个迁移,将status 列从整数转换为枚举。

execute "CREATE TYPE status_options AS ENUM ('pending', 'declined', 'approved');"
change_column :site_applications, :status, "status_options USING status::status_options"

但是,我得到了这个错误:

PG::CannotCoerce: ERROR:  cannot cast type integer to status_options
ALTER TABLE "site_applications" ALTER COLUMN "status" TYPE status_options USING status::status_options

到目前为止,我在搜索中看到的所有内容都告诉我应该有效,但事实并非如此。我想也许问题是我不能从整数到枚举。随它吧。我的解决方案是首先将列转换为字符串,然后然后尝试将其转换为枚举。

change_column :site_applications, :status, :string
execute "CREATE TYPE status_options AS ENUM ('pending', 'declined', 'approved');"
change_column :site_applications, :status, "status_options USING status::status_options"

这给了我以下错误:

PG::DatatypeMismatch: ERROR:  default for column "status" cannot be cast automatically to type status_options
ALTER TABLE "site_applications" ALTER COLUMN "status" TYPE status_options USING status::status_options

这让我相信这与默认值有关,因此我尝试在 change_column 声明中指定默认值:

change_column :site_applications, :status, :string, default: "pending"

这成功地将列更改为默认为“待定”的字符串,但 change_column 失败并出现相同的“列默认”错误。

我意识到我可以简单地将列放在一起,然后完全按照我的意愿重新创建它,但在这一点上,这是后人的问题。为什么我不能将列从整数或字符串转换为枚举?有人吗?

接受答复后更新

根据 Gary 的回答,这是有效的迁移。

def up
  execute "ALTER TABLE site_applications ALTER status DROP DEFAULT;"
  execute "CREATE TYPE status_options AS ENUM ('pending', 'declined', 'approved');"
  change_column :site_applications, :status, "status_options USING status::status_options", default: "pending"
end

def down
  change_column :site_applications, :status, :string, default: "pending"
  execute "DROP TYPE status_options;"
end

【问题讨论】:

  • 你能在 PSQL 中显示 \dt site_applications 的结果吗?因为该消息听起来像是针对该列设置了默认值。您可能需要在进行更改时删除默认值,然后再添加适当类型的默认值。
  • @Gary 我认为你是绝对正确的,但我无法一辈子弄清楚要设置什么类型的默认值以便可以将其切换为枚举。但是,我做了\dt schema.site_applications,这就是它返回的内容:schema | site_applications | table | eliduke
  • 对不起,应该是 \d 而不是 \dt
  • 哦,好的。就是这样:status | integer | not null default 0。但我对此并不感到惊讶,真的,因为当我尝试将整数转换为枚举时,我得到了错误cannot cast type integer to status_options。因此,我认为由于枚举是字符串的一种变体,因此我首先将其转换为字符串,然后再转换为枚举。那是我收到default for column 错误的时候。有一次我什至尝试将整数转换为字符串并将字符串列的默认值设置为 nil,然后转换为枚举。这也失败了,同样的错误。
  • 在这种情况下,您想发出alter table schema.site_applications alter status drop default 以完全删除默认值。转换类型,然后alter table schema.site_applications alter status set default 'pending'::status_options' 不完全确定默认枚举语法。

标签: ruby-on-rails postgresql enums


【解决方案1】:

您需要在更改之前从列中删除默认值,因为默认值设置为对旧列类型有效但与新类型不兼容的值。

alter table schema.site_applications alter status drop default

然后您可以更改列类型。最后,一旦应用了新的列类型,您就可以为表添加新的默认值。

alter table schema.site_applications alter status set default 'pending'::status_options

【讨论】:

    猜你喜欢
    • 2018-02-14
    • 2017-04-30
    • 1970-01-01
    • 1970-01-01
    • 2020-04-04
    • 1970-01-01
    • 2016-06-13
    • 1970-01-01
    • 2017-10-13
    相关资源
    最近更新 更多