如何将Rails中的数据库中的数据从字符串类型更改为ID类型 —— MySQL

3

你好,我有一个简单的问题,也许并不简单......

背景:我想要用数据库(mysql)替换掉yaml文件中的状态,因此在用户表中创建了名为"status"的列。当我将逻辑替换为数据库时,我创建了一个名为Status的模型,创建了一个表,并配置了与用户的关系......

问题描述:当我在用户表中创建了status_id列后,我现在有两个列:"status"和"status_id"。"status"列是字符串类型,有很多字符串值,例如"confirmed"。请问如何(使用种子迁移和状态)填充"status_id"列。我的意思是,如果"status"列有值"confirmed",我希望"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

用户属于 :状态

状态有多个用户


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

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

2个回答

3
给出以下(您的)示例数据:
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语句会更新users表中的status_id列,将其值更新为来自statuses表的相应值:

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 :) - Skrypter
哦,感谢您的点赞,但是我不知道如何使用Rails完成这个问题,所以您可能需要等待其他答案。 - PerlDuck

0

这听起来像是一次性的数据迁移,可以通过几种不同的方式处理。其中一种方法是编写一个一次性脚本或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任务。添加Seed Migration并使用sql(类似于“execute”)获取所有状态(它们是字符串),并将它们与状态表进行比较(例如,“confirmed”=“confirmed”),然后使用关系将status.name更改为status.id,并将它们推送到数据库中。我仍然不知道如何做到这一点...但我知道这是最简单的方法,并且Open/Close原则将得以维护。 - Skrypter
你要求使用Rails来完成这个任务。我不确定使用种子文件是最好的方式,也不知道你是否想按照你描述的方式更改列。一旦你完成了数据更改,你可以运行迁移或任务来从用户中删除status.name。但是,你需要确保你采取的任何方法都允许将来在不同环境下部署你的应用程序,例如让你无缝运行迁移。 - margo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接