Jak przenieść kolumnę (z zawartością) do innej tabeli podczas migracji Rails?
Muszę przenieść kilka kolumn z jednej istniejącej tabeli do drugiej. Jak to zrobić za pomocą migracji 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
Powyższe tworzy tylko nowe kolumny, ale wartości pozostają puste...
Chcę uniknąć logowania się do bazy danych, aby ręcznie aktualizować tabele.
Jeśli istnieje sposób programowego przesuwania wartości kolumn, jakie są charakterystyki wydajności? Czy zrobiłby to wiersz po wierszu, czy jest sposób na hurtową aktualizację?
7 answers
W końcu skorzystałem z tej migracji (przetestowany, działa i z powodzeniem powraca):
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
Podoba mi się, ponieważ unika aktualizacji wiersz po wierszu w dużej bazie danych.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-26 09:04:57
Zrobiłbym to jako trzy migracje, lub trzyczęściowa migracja. Pierwsza część to dodawanie kolumny, druga część to kopiowanie danych, a trzecia część to opuszczanie kolumny.
Wygląda na to, że środkowy krok jest tym, o co prosisz, możesz to zrobić w Rubim poprzez zapętlenie wszystkich użytkowników i ustawienie właściwości, tak:
Users.each do |user|
user.someprop = user.profile.some_prop
user.save
end
Nie podoba mi się ten sposób robienia tego, ponieważ jest to bardzo powolne. Sugerowałbym wykonanie surowego sql ' a w ten sposób:
execute "UPDATE users u, profiles p SET u.someprop=p.someprop WHERE u.id=p.user_id"
Te oba zakładają coś o Profilu / Stowarzyszenie użytkowników, które można dostosować, jeśli założyłem źle.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-26 08:25:05
Możesz uniknąć zakodowanych, specyficznych dla bazy danych poleceń sql za pomocą update_all i/lub find_each
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-13 16:10:29
Składnia nie działa w późniejszych wersjach Postgres. Aby uzyskać zaktualizowaną odpowiedź @Eero dla postów 9.4.5 wykonaj następujące czynności:
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-26 16:34:28
Następująca składnia UPDATE
działa dla ostatnich wersji Postgres i unika subquery:
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-05 12:14:41
To właśnie zrobiłem w moim projekcie: -
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-31 17:26:41
Dla mnie (postgreSQL 9.1) surowy SQL nie działał. Zmieniłem:
" UPDATE users u
SET someprop = (SELECT p.someprop
FROM profiles p
WHERE u.id = p.user_id );"
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-08 16:17:00