我在Postgres数据库的表中有一个布尔类型的列。我想将其改为整数类型,因为该列需要更多的信息而不仅仅是真/假。
我还希望将所有的真值更改为1,将所有的假值更改为2。
这在Rails中是否容易实现?我试图通过迁移文件和迁移我的数据库来实现这一点。
我在Postgres数据库的表中有一个布尔类型的列。我想将其改为整数类型,因为该列需要更多的信息而不仅仅是真/假。
我还希望将所有的真值更改为1,将所有的假值更改为2。
这在Rails中是否容易实现?我试图通过迁移文件和迁移我的数据库来实现这一点。
是的,你可以用单个迁移来实现此更改。唯一棘手的部分是需要告诉数据库如何将布尔值转换为整数。
要做到这一点,可以在ALTER TABLE
中使用USING
子句提供映射关系。原始SQL版本如下:
alter table models
alter column c type integer
using case when c then 1 else 2 end
并且这意味着迁移就是这样:
def change
change_column :models, :c, :integer, :using => 'case when c then 1 else 2 end'
end
布尔列只能包含TRUE
或FALSE
,所以简单的CASE
应该就足够了。如果您允许NULL
并想要保留它们,则:
:using => 'case when c is null then null when c then 1 else 2 end'
应该会奏效。
当然,您将需要手动更新所有代码,以使其与这些新整数正常工作。
您真的需要修改数据库吗?一种可能的解决方法是只需创建一个包装器方法来为您处理此操作。假设您有一个名为mycol
的布尔列,则可以编写一个包装器方法,它在不修改基础数据库的情况下透明地处理此逻辑。
在您的ActiveRecord模型中:
def mycol
read_attribute(:boolcol) ? 1 : 2
end
def mycol=(value)
write_attribute(:mycol, value == 1)
end
例如,运行u.mycol = 1 && u.save
会将false
写入数据库,而将返回1。
但是,如果真的有必要进行迁移,则创建一个新的整数列来取代原始的布尔列。不要删除或修改现有的列,因为这样可以确保您不会破坏或销毁数据。
创建新列之后,请创建一个rake任务来遍历所有现有记录(使用find_each
方法进行迭代),并根据原始布尔列的值设置新列的整数值。一旦验证了数据的完整性,就可以删除原始布尔列并用新创建的列替换它。