如何在 Rails 迁移中将列(包含内容)移动到另一个表?

发布于 2024-11-09 23:18:08 字数 442 浏览 0 评论 0原文

我需要将一些列从一个现有表移动到另一个表。如何使用 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

上面只是创建了新列,但值保留为空...

我想避免登录数据库来手动更新表。

如果有一种方法可以以编程方式移动列值,那么性能特征是什么?是逐行更新还是有办法批量更新?

I need to move some columns from one existing table to another. How do I do it using a 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

The above just creates the new columns, but values are left empty...

I want to avoid logging in to the database to manually update the tables.

If there is a way to move column values programmatically, what are the performance characteristics? Would it do row-by-row, or is there a way to update in bulk?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

浅浅 2024-11-16 23:18:08

我最终使用了这种迁移(经过测试,它有效,并且成功回滚):

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

我喜欢它,因为它避免了大型数据库上的逐行更新。

I ended up using this migration (tested, it works, and rolls back successfully):

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

I like it because it avoids the row-by-row updates on a large database.

人生戏 2024-11-16 23:18:08

以下 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

The following UPDATE syntax works for recent Postgres versions and avoids a 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
他不在意 2024-11-16 23:18:08

我会将其作为三个迁移或三部分迁移来完成。第一部分是添加列,第二部分是复制数据,第三部分是删除列。

听起来中间步骤就是您要问的,您可以通过循环所有用户并设置属性来在 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"

这些都假设有关您的个人资料/用户关联的一些信息,如果我假设错误,您可以调整它。

I would do this as three migrations, or a three part migration. The first part is adding the column, the second part is copying data over, and the third part is dropping the column.

It sounds like the middle step is what you're asking about, you can do this in ruby by looping over all users and setting the property, like this:

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

I don't love this way of doing it, because it is seriously slow. I would suggest executing raw sql like this:

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

These both assume something about your profile/user association, which you can adjust if I assumed wrong.

太阳哥哥 2024-11-16 23:18:08

该语法不适用于更高版本的 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

The syntax does not work for later versions of Postgres. For an updated answer of @Eero's for Postges 9.4.5 do the following:

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
夏有森光若流苏 2024-11-16 23:18:08

您可以使用 update_all 来避免硬编码、数据库特定的 sql 语句/或 find_each

You can avoid the hard coded, database specific sql statements with update_all and/or find_each

巡山小妖精 2024-11-16 23:18:08

这就是我在项目中所做的:-

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

This is what I did in my project:-

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
温柔女人霸气范 2024-11-16 23:18:08

对于我(postgreSQL 9.1)来说,RAW SQL 不起作用。我已经改变了它:

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

For me (postgreSQL 9.1) the RAW SQL didn't worked. I've changed it:

" UPDATE users u
  SET someprop = (SELECT p.someprop
                  FROM profiles p
                  WHERE u.id = p.user_id );"
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文