Rails迁移 – types转换的change_column
我已经google'd一点点,似乎有没有令人满意的答案我的问题。
我有一个stringtypes的列的表。 我想运行以下迁移:
class ChangeColumnToBoolean < ActiveRecord::Migration def up change_column :users, :smoking, :boolean end end
当我运行这个时,我得到以下错误
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
我知道我可以使用纯SQL执行此迁移,但是如果我可以使用Rails来完成,那么仍然会更好。 我经历了Rails代码,似乎没有这种可能性,但也许有人知道一种方式?
我不感兴趣: – 纯SQL – 删除列 – 创build另一列,转换数据,删除原来的,然后重命名
如果smoking
列中的string已经是有效的布尔值,则以下语句将更改列types而不会丢失数据:
change_column :users, :smoking, 'boolean USING CAST(smoking AS boolean)'
同样,您可以使用此语句将列转换为整数:
change_column :table_name, :column_name, 'integer USING CAST(column_name AS integer)'
我正在使用Postgres。 不知道这个解决scheme是否适用于其他数据库。
并不是所有的数据库都允许更改列types,通常采取的方法是添加所需types的新列,将所有数据传入,删除旧列并重命名新列。
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
所以在postgres中的布尔值是正确的:
change_column :table_name, :field,'boolean USING (CASE field WHEN \'your any string as true\' THEN \'t\'::boolean ELSE \'f\'::boolean END)'
而且你可以在你的表情中添加更多的WHEN
– THEN
条件
对于其他数据库服务器,expression式将基于数据库服务器的语法来构造,但原理是相同的。 只有手动转换algorithm,完全没有SQL,不幸的是不够。
带语法的方法change_column :table, :filed, 'boolean USING CAST(field AS boolean)'
只适用于字段内容如下:true / false / null
由于我正在使用Postgres,所以我现在用SQL解决scheme。 使用的查询:
execute 'ALTER TABLE "users" ALTER COLUMN "smoking" TYPE boolean USING CASE WHEN "flatshare"=\'true\' THEN \'t\'::boolean ELSE \'f\'::boolean END'
它只适用于一个字段填充了真/假string(比如默认的单选button集合助手,强制布尔types会生成)