我有一张桌子,我们称之为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来实现的。但是,我很想知道是否可以一次性完成。
答案 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