如何在Rails迁移中将列(包含内容)移动到另一个表?

我需要将一些列从一个现有表移动到另一个表。 如何使用rails迁移执行此操作?

class AddPropertyToUser < ActiveRecord::Migration def self.up add_column :users, :someprop, :string remove_column :profiles, :someprop end def self.down add_column :profiles, :someprop, :string remove_column :users, :someprop end end 

以上只是创建新列,但值保持为空…

我想避免登录到数据库以手动更新表。

如果有一种以编程方式移动列值的方法,那么性能特征是什么? 它会逐行进行,还是有办法大量更新?

我最终使用了这个迁移(测试,它工作,并成功回滚):

 class AddPropertyToUser < ActiveRecord::Migration def self.up add_column :users, :someprop, :string execute "UPDATE users u, profiles p SET u.someprop = p.someprop WHERE u.id = p.user_id" remove_column :profiles, :someprop end def self.down add_column :profiles, :someprop, :string execute "UPDATE profiles p, users u SET p.someprop = u.someprop WHERE p.user_id = u.id" remove_column :users, :someprop end end 

我喜欢它,因为它避免了大型数据库上的逐行更新。

我会这样做三次迁移,或三次迁移。 第一部分是添加列,第二部分是复制数据,第三部分是删除列。

这听起来像你要问的中间步骤,你可以通过循环遍历所有用户并设置属性来在ruby中执行此操作,如下所示:

 Users.each do |user| user.someprop = user.profile.some_prop user.save end 

我不喜欢这种做法,因为它非常慢。 我建议像这样执行原始的sql:

 execute "UPDATE users u, profiles p SET u.someprop=p.someprop WHERE u.id=p.user_id" 

这些都假设您的个人资料/用户关联,如果我认为错误,您可以调整。

您可以使用update_all和/或find_each来避免硬编码的,特定于数据库的sql语句

该语法不适用于Postgres的更高版本。 有关@Eero的Postges 9.4.5的更新答案,请执行以下操作:

 class AddPropertyToUser < ActiveRecord::Migration def self.up add_column :users, :someprop, :string execute "UPDATE users u SET someprop = (SELECT p.someprop FROM profiles p WHERE u.id = p.user_id);" remove_column :profiles, :someprop end def self.down add_column :profiles, :someprop, :string execute "UPDATE profiles p SET someprop = (SELECT u.someprop FROM users u WHERE p.user_id = u.id);" remove_column :users, :someprop end end 

以下UPDATE语法适用于最近的Postgres版本并避免使用子查询:

 class MoveSomePropertyToUser < ActiveRecord::Migration def self.up add_column :users, :some_property, :string execute "UPDATE users u SET some_property = p.some_property FROM profiles p WHERE u.id = p.user_id;" remove_column :profiles, :some_property end def self.down add_column :profiles, :some_property, :string execute "UPDATE profiles p SET some_property = u.some_property FROM users u WHERE p.user_id = u.id;" remove_column :users, :some_property end end 

这就是我在项目中所做的: –

 class MoveColumnDataToUsersTable < ActiveRecord::Migration[5.1] def up add_column :users, :someprop, :string User.find_each do |u| Profile.create!(user_id: u.id, someprop: someprop) end remove_column :profiles, :someprop end def down add_column :profiles, :someprop, :someprop_data_type Profile.find_each do |p| User.find_by(id: p.user_id).update_columns(someprop: p.someprop) end Profile.destroy_all end end 

对我来说(postgreSQL 9.1),RAW SQL没有用。 我改变了它:

 " UPDATE users u SET someprop = (SELECT p.someprop FROM profiles p WHERE u.id = p.user_id );"