いくつかの列を既存のテーブルから別のテーブルに移動する必要があります。 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
大規模なデータベースでの行ごとの更新を回避できるので、私はそれが好きです。
これは、3つの移行、または3つの部分の移行として行います。最初の部分は列の追加、2番目の部分はデータのコピー、3番目の部分は列の削除です。
真ん中のステップがあなたが求めているもののようです。これは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
構文は、最近の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
この構文は、Postgresのそれ以降のバージョンでは機能しません。 Postges 9.4.5の@Eeroの最新の回答については、次のようにしてください。
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
これは私が私のプロジェクトでしたことです:-
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