将没有默认值的NOT NULL字段添加到填充的DB中

时间:2014-02-27 15:18:50

标签: ruby-on-rails ruby rails-activerecord

我有一张桌子,我们称之为MyTable。它是Postgresql数据库的一部分。

MyTable中有很多条目,比方说超过一百万。我想在这个表中添加一个字段,我们称之为MyNewField。它将由ActiveRecord Migration添加。

此字段没有默认值且不可为空。结果,在它的迁移类中会是这样的:

class AddMyFieldToMyTable < ActiveRecord::Migration
  def change
    add_column :my_table, :my_field, :text, null: false
  end
end

但是,它会触发错误(PG :: NotNullViolation),因为该表已包含行,所有行都将MyField设置为NULL。

我想要做的是:添加没有默认值的行和nullable设置为false(不触发PG :: NotNullViolation)。然后,将另一个表中的值插入到每个记录中。

这可能是通过将可空设置为true的字段添加,然后添加值,然后更改回nullable设置为false来实现的。但是,我很想知道是否可以一次性完成。

2 个答案:

答案 0 :(得分:6)

您必须确保另一个表的my_field值为my_table中的每个条目。

class AddMyFieldToMyTable < ActiveRecord::Migration
  def up
    add_column :my_table, :my_field, :text
    execute("insert into my_table(my_field) values (select my_field from different_table where my_table.id = different_table.different_id)")
    change_column :my_table, :my_field, :text, null: false
  end

  def down
    remove_column :my_table, :my_field
  end
end

答案 1 :(得分:1)

所有迹象似乎表明,可以一次性完成;你必须添加没有空约束的列,填充数据,然后添加空约束。

class AddMyFieldToMyTable < ActiveRecord::Migration
  def change
    add_column :my_table, :my_field, :text
    reversible do |dir|
      dir.up do
        # populate my_field col
        change_column :my_table, :my_field, :text, null: false
      end
    end
  end
end

资源:


如果你真的只想设置一次列,也许你可以使用临时默认值生成它,然后立即用真实数据更新它。

class AddMyFieldToMyTable < ActiveRecord::Migration
  def change
    add_column :my_table, :my_field, :text, default: 'tmp', null: false
    reversible do |dir|
      dir.up do
        # populate my_field col
      end
    end
  end
end