2

我总是冒着破坏我的开发数据库(PostgreSQL)并重建它的风险,但我想我会先问一下是否有人有经验。

理想情况下,所有数据都将被截断为其整数:(例如:5.7 将变为 5)或者它可能会将值四舍五入(5.7 变为 6)?或者它只是简单地取消或清零所有值并且数据丢失?我想最坏的结果将是不可靠的数据(5.7 变为 23)。

这些类型的迁移是否有一般的经验法则?

class ChangeBookFromDecimalToInteger < ActiveRecord::Migration
  def self.up
   change_column :book, :price, :integer
  end

  def self.down
   change_column :book, :price, :decimal
  end
end
4

3 回答 3

7

ActiveRecord 将发送一个 ALTER TABLE ALTER COLUMN ... TYPE 到数据库,数据库将执行类型转换。PostgreSQL 将转换decimalintusing round

=> create table with_decimal (n decimal(11, 6));
=> insert into with_decimal (n) values (1.0),(1.1),(1.5),(1.6),(1.9);
=> insert into with_decimal (n) values (-1.0),(-1.1),(-1.5),(-1.6),(-1.9);
=> select * from with_decimal;
     n     
-----------
  1.000000
  1.100000
  1.500000
  1.600000
  1.900000
 -1.000000
 -1.100000
 -1.500000
 -1.600000
 -1.900000
(10 rows)

=> alter table with_decimal alter column n type int;
=> select * from with_decimal;
 n  
----
  1
  1
  2
  2
  2
 -1
 -1
 -2
 -2
 -2
(10 rows)

请注意,round(numeric)四舍五入到最接近的整数。

如果您想要特定的转换行为,您应该在ALTER TABLE中使用 USING 来说明:

可选USING子句指定如何从旧列值计算新列值;如果省略,则默认转换与从旧数据类型到新数据类型的赋值转换相同。如果USING没有从旧类型到新类型的隐式或赋值转换,则必须提供子句。

如果您需要一个 USING 子句,则必须手动发出 ALTER TABLE,因为 ActiveRecord 对 USING 一无所知,例如:

def up
    connection.execute(%q{
        alter table books
        alter column price 
        type integer
        using trunc(price * 100)
    })
end
于 2013-01-19T20:39:09.710 回答
0

您需要查阅 PostreSQL 手册,了解它如何处理诸如“ALTER TABLE ... CHANGE COLUMN ...”之类的查询,以及它如何在相应类型之间转换数据。
Rails 中的所有 DB Schema 更改迁移都由相应的数据库后端处理。

于 2013-01-19T20:20:30.550 回答
0

一般的经验法则是,如果您必须迁移,并且需要明确的要求,请创建新列,使用 Ruby 转换列,然后删除旧列。如果您不关心数据,请让数据库通过ALTER TABLE

于 2013-01-19T20:38:35.440 回答