Rails迁移 - 带有类型转换的change_column

Mik*_*del 53 ruby-on-rails ruby-on-rails-3

我已经谷歌了一下,似乎对我的问题没有令人满意的答案.

我有一个表格,其中包含string类型的列.我想运行以下迁移:

class ChangeColumnToBoolean < ActiveRecord::Migration
    def up
        change_column :users, :smoking, :boolean
    end
end
Run Code Online (Sandbox Code Playgroud)

当我运行这个时,我得到以下错误

PG::Error: ERROR:  column "smoking" cannot be cast automatically to type boolean
HINT:  Specify a USING expression to perform the conversion.
: ALTER TABLE "users" ALTER COLUMN "smoking" TYPE boolean
Run Code Online (Sandbox Code Playgroud)

我知道我可以使用纯SQL执行此迁移,但如果我可以使用Rails执行此操作仍然会更好.我经历了Rails代码,似乎没有这种可能性,但也许有人知道一种方式?

我对以下内容不感兴趣: - 纯SQL - 删除列 - 创建另一列,转换数据,删除原始然后重命名

Bri*_*ian 108

如果smoking列中的字符串已经是有效的布尔值,则以下语句将更改列类型而不会丢失数据:

change_column :users, :smoking, 'boolean USING CAST(smoking AS boolean)'
Run Code Online (Sandbox Code Playgroud)

同样,您可以使用此语句将列转换为整数:

change_column :table_name, :column_name, 'integer USING CAST(column_name AS integer)'
Run Code Online (Sandbox Code Playgroud)

我正在使用Postgres.不确定此解决方案是否适用于其他数据库.

  • 只是为了避免任何人混淆:是的,你说两次你的新专栏.把它想象成确认你想要这样做而不是说明如何将foo变成bool (2认同)

Mat*_*att 34

并非所有数据库都允许更改列类型,通常采用的方法是添加所需类型的新列,引入任何数据,删除旧列并重命名新列.

add_column :users, :smoking_tmp, :boolean

User.reset_column_information # make the new column available to model methods
User.all.each do |user|
  user.smoking_tmp = user.smoking == 1 ? true : false # If smoking was an int, for example
  user.save
end

# OR as an update all call, set a default of false on the new column then update all to true if appropriate.
User.where(:smoking => 1).update_all(:smoking_tmp = true) 

remove_column :users, :smoking
rename_column :users, :smoking_tmp, :smoking
Run Code Online (Sandbox Code Playgroud)


Ден*_*кин 8

所以对于postgres中的布尔值是正确的:

change_column :table_name, :field,'boolean USING (CASE field WHEN \'your any string as true\' THEN \'t\'::boolean ELSE \'f\'::boolean END)'
Run Code Online (Sandbox Code Playgroud)

并且你可以在表达式中添加更多WHEN- THEN条件

对于其他数据库服务器,将根据数据库服务器的语法构造表达式,但原理是相同的.只有手动转换算法,完全没有SQL,遗憾的是还不够.

change_column :table, :filed, 'boolean USING CAST(field AS boolean)'只有当字段的内容类似于:true/false/null时,语法方式才适用


Mik*_*del 5

因为我正在使用Postgres,所以我现在使用SQL解决方案.使用的查询:

    execute 'ALTER TABLE "users" ALTER COLUMN "smoking" TYPE boolean USING CASE WHEN "flatshare"=\'true\' THEN \'t\'::boolean ELSE \'f\'::boolean END'
Run Code Online (Sandbox Code Playgroud)

只有当一个字段填充了真/假字符串时(例如生成强制布尔类型的默认单选按钮集合助手),它才有效

  • @DonnyP如果“重建数据库”你的意思是“重建数据库的模式” - 推荐的方法是通过 `rake db:struct:load` / `rake db:schema:load` 而不是通过运行 all迁徙。 (2认同)