Подтвердить что ты не робот

Как переместить столбец (с содержимым) в другую таблицу при миграции 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

Вышеуказанные просто создают новые столбцы, но значения остаются пустыми...

Я хочу избежать входа в базу данных, чтобы вручную обновлять таблицы.

Если есть способ программно изменить значения столбца, каковы характеристики производительности? Будет ли это делать по строкам, или есть способ обновления навалом?

4b9b3361

Ответ 1

Я закончил использовать эту миграцию (протестировал, работает и откатывается успешно):

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

Мне нравится, потому что он избегает пошаговых обновлений в большой базе данных.

Ответ 2

Я бы сделал это как три миграции, или миграцию из трех частей. Первая часть - это добавление столбца, вторая часть - копирование данных, а третья часть - столбца.

Похоже, что средний шаг - это то, о чем вы спрашиваете, вы можете сделать это в рубине, перейдя по всем пользователям и установив свойство, например:

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

Я не люблю этот способ делать это, потому что он серьезно медленный. Я бы предложил выполнить raw sql следующим образом:

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

Они оба предполагают что-то о вашей ассоциации профиля/пользователя, которую вы можете настроить, если я ошибаюсь.

Ответ 3

Вы можете избежать жестких, специфичных для базы данных операторов sql с update_all и/или find_each

Ответ 4

Синтаксис не работает для более поздних версий Postgres. Для получения обновленного ответа от @Eero for 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

Ответ 5

Следующий синтаксис 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

Ответ 6

Для меня (postgreSQL 9.1) RAW SQL не работал. Я изменил его:

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