将布尔列类型更改为整数

6

我在Postgres数据库的表中有一个布尔类型的列。我想将其改为整数类型,因为该列需要更多的信息而不仅仅是真/假。

我还希望将所有的真值更改为1,将所有的假值更改为2。

这在Rails中是否容易实现?我试图通过迁移文件和迁移我的数据库来实现这一点。


这听起来像是一个 XY 问题,你在问 Y,但应该问 X,而 X 导致了 Y。换句话说,你应该询问你正在存储的模式和数据以及为什么,而不是修改表并尝试将 true 和 false 映射到整数,然后在同一字段中使用其他内容。 - the Tin Man
2个回答

21

是的,你可以用单个迁移来实现此更改。唯一棘手的部分是需要告诉数据库如何将布尔值转换为整数。

要做到这一点,可以在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

布尔列只能包含TRUEFALSE,所以简单的CASE应该就足够了。如果您允许NULL并想要保留它们,则:

:using => 'case when c is null then null when c then 1 else 2 end'

应该会奏效。

当然,您将需要手动更新所有代码,以使其与这些新整数正常工作。


3

您真的需要修改数据库吗?一种可能的解决方法是只需创建一个包装器方法来为您处理此操作。假设您有一个名为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方法进行迭代),并根据原始布尔列的值设置新列的整数值。一旦验证了数据的完整性,就可以删除原始布尔列并用新创建的列替换它。


1
谢谢,那很有道理 :) (我会遵循第二个建议) - learningruby347
谢谢!你是对的。安全第一,比后悔强。 - learningruby347
为什么要费力地手动转换布尔值,当数据库可以通过ALTER TABLE中的简单USING子句轻松完成呢? - mu is too short
此外,在 rake 任务中访问 Rails 环境的能力可以提供灵活性和控制。当然,这也有一些缺点。 - Anthony E
然而,你的方法有一个重要的优点,那就是它应该是原子和线程安全的,尽管它会锁定表直到完成。你可以在ActiveRecord中为此编写一个事务,但这有点危险。 - Anthony E
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接