【问题标题】:how to change data in db from string to id - Rails, Mysql如何将 db 中的数据从字符串更改为 id - Rails,Mysql
【发布时间】:2016-04-30 15:14:19
【问题描述】:

你好,我可能有简单的问题,也许不是......

历史记录:我想将 yaml 文件替换为 db(mysql) 的状态,并且我在用户表列中有:状态。当我将逻辑替换为数据库时,我已经创建了模型状态、创建表并配置了与用户的关系......

描述问题:当我在用户表中创建 status_id 时,我有 2 列:“status”和“status_id”。 “status”列是字符串,有很多字符串值,例如“confirmed”。如何(使用带有状态的种子迁移)并填写“status_id”列。我的意思是,如果“status”列的值“已确认”,我想在“status_id”列中包含值:1。

statuses table:
id name
1   confirmed
2   not confirmed
3   something else


Users table
id status           status_id
1  confirmed        empty
2  confirmed        empty
3  confirmed        empty
4  not confirmed    empty
5  not confirmed    empty
6  something else   empty
7  something else   empty

用户属于_to :status

状态 has_many :users


问题: 为什么我不只是更改名称并在“状态”列中输入 数据类型为“id”的“status_id”?

回答: 因为我需要使用 capistrano 将其部署到生产环境 服务器,我不能丢失数据并从状态列中删除数据。

【问题讨论】:

    标签: mysql ruby-on-rails database yaml rails-migrations


    【解决方案1】:

    鉴于以下(您的)样本数据:

    create table statuses (id int, name char(20));
    insert into statuses (id, name) values
        (1, 'confirmed'),
        (2, 'not confirmed'),
        (3, 'something else');
    
    create table users (id int, status char(20), status_id int);
    insert into users (id, status) values
        (1,'confirmed'),
        (2,'confirmed'),
        (3,'confirmed'),
        (4,'not confirmed'),
        (5,'not confirmed'),
        (6,'something else'),
        (7,'something else');
    
    select * from users;
    +------+----------------+-----------+
    | id   | status         | status_id |
    +------+----------------+-----------+
    |    1 | confirmed      |      NULL |
    |    2 | confirmed      |      NULL |
    |    3 | confirmed      |      NULL |
    |    4 | not confirmed  |      NULL |
    |    5 | not confirmed  |      NULL |
    |    6 | something else |      NULL |
    |    7 | something else |      NULL |
    +------+----------------+-----------+
    7 rows in set (0.00 sec)
    

    update 语句使用来自statuses 的适当值更新users 中的status_id 列:

    update users u 
       set u.status_id=(select s.id from statuses s where u.status=s.name);
    Query OK, 7 rows affected (0.01 sec)
    Rows matched: 7  Changed: 7  Warnings: 0
    
    select * from users;
    +------+----------------+-----------+
    | id   | status         | status_id |
    +------+----------------+-----------+
    |    1 | confirmed      |         1 |
    |    2 | confirmed      |         1 |
    |    3 | confirmed      |         1 |
    |    4 | not confirmed  |         2 |
    |    5 | not confirmed  |         2 |
    |    6 | something else |         3 |
    |    7 | something else |         3 |
    +------+----------------+-----------+
    7 rows in set (0.00 sec)
    

    希望这是您所要求的,因为我的回答既不涉及 ruby​​、yaml 也不涉及 rails。

    【讨论】:

    • 好的……它是正确的,但是……我需要用 ruby​​ on rails 写的这个答案……比如使用 update_attribute 或类似的东西。但是对于答案 +1 :)
    • 哦,感谢您的 +1,但恐怕您必须等待其他答案,因为我不知道如何使用 rails 完成此操作。
    【解决方案2】:

    这听起来像是一次性的数据迁移,可以通过多种不同的方式进行处理。一种方法是编写一次性脚本或 rake 任务来更新所有用户。

    some_task.rake

    desc 'Add status id to existing users'
    
    namespace :users do
      task assign_status: :environment do
        statuses = {}
        Status.all.each {|status| statuses[status.name] = status.id}
        User.all.each do |user|
          user.update_attribute(status_id: statuses[user.status])
        end
      end
    end
    

    如果您有很多用户,您可能希望使用find_each,因为它使用批处理,所以性能更高。您可能还想在 rake 任务中添加某种进度报告。

    这种方法允许您针对现有数据库的副本测试任务。

    【讨论】:

    • 你快到了……但我没有创建 rake 任务,而是找到了更好的方法。添加种子迁移并使用 sql(类似“execute”)获取所有状态(它们是字符串)并将它们与状态表(如“confirmed”=“confirmed”)进行比较,然后使用关系将 status.name 更改为 status.id并将它们推送到数据库。我仍然不知道该怎么做……但我知道它最简单的方法,并且将保持打开/关闭原则。
    • 您要求用 Rails 实现此目的。我不确定使用种子文件是最好的方法,我不知道您是否想以您描述的方式更改列。完成数据更改后,您可以运行迁移或任务以从用户中删除 status.name。但是,您将希望确保您采取的任何方法都允许将来将您的应用程序部署到不同的环境,例如让您无缝运行迁移。
    猜你喜欢
    • 1970-01-01
    • 2020-05-18
    • 1970-01-01
    • 2011-09-30
    • 1970-01-01
    • 2015-01-14
    • 2023-03-10
    • 2023-03-20
    • 2016-07-13
    相关资源
    最近更新 更多