34

既存のテーブルから別のテーブルにいくつかの列を移動する必要があります。rails migration を使用してどうすればいいですか?

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

上記は新しい列を作成するだけですが、値は空のままです...

テーブルを手動で更新するためにデータベースにログインすることを避けたいです。

列の値をプログラムで移動する方法がある場合、パフォーマンスの特徴は何ですか? 行ごとに実行しますか、それとも一括更新する方法はありますか?

4

7 に答える 7

40

私はこの移行を使用することになりました(テスト済み、動作し、正常にロールバックします):

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

大規模なデータベースで行ごとの更新を回避できるため、気に入っています。

于 2011-05-26T09:04:57.180 に答える
8

これは、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"

これらは両方とも、プロファイルとユーザーの関連付けについて何かを想定しています。これは、私が間違っていると想定した場合に調整できます。

于 2011-05-26T08:25:05.230 に答える
5

この構文は、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
于 2016-01-26T16:34:28.730 に答える
2

update_allおよび/またはfind_eachを使用して、ハードコーディングされたデータベース固有の SQL ステートメントを回避できます。

于 2012-11-13T16:10:29.773 に答える