Как переместить столбец (с содержимым) в другую таблицу при миграции 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
Вышеуказанные просто создают новые столбцы, но значения остаются пустыми...
Я хочу избежать входа в базу данных, чтобы вручную обновлять таблицы.
Если есть способ программно изменить значения столбца, каковы характеристики производительности? Будет ли это делать по строкам, или есть способ обновления навалом?
Ответы
Ответ 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 );"