【问题标题】:How to rename a column and change its type by migration same time如何通过迁移同时重命名列并更改其类型
【发布时间】:2012-11-20 09:58:42
【问题描述】:

在我的general_exams 表中,我有一个名为semester 的列,类型为string。现在我想把它的名字改成semester_id,类型是integer。我已阅读有关迁移的信息,并且它具有可用的转换:

  • rename_column(table_name, column_name, new_column_name):重命名列,但保留类型和内容。
  • change_column(table_name, column_name, type, options):使用与 add_column 相同的参数将列更改为不同的类型。

所以,我像这样创建我的迁移文件:

class RenameSemesterFromGeneralExams < ActiveRecord::Migration

  def change
    rename_column :general_exams, :semester, :semester_id
    change_column :general_exams, :semester_id, :integer
  end
end

但是,当我运行rake db:migrate 时,它有错误:

==  RenameSemesterFromGeneralExams: migrating =================================
-- rename_column(:general_exams, :semester, :semester_id)
   -> 0.0572s
-- change_column(:general_exams, :semester_id, :integer)
rake aborted!
An error has occurred, this and all later migrations canceled:

PG::Error: ERROR:  column "semester_id" cannot be cast to type integer
: ALTER TABLE "general_exams" ALTER COLUMN "semester_id" TYPE integer

在我的 GeneralExam 表中,我销毁了所有数据。 那么,任何人都可以告诉我我该怎么做?还是我必须创建两个迁移文件?

【问题讨论】:

  • 这个问题实际上很有帮助,因为除了其中的错误之外,它还准确地指定了如何更改列名并输入问题本身!

标签: ruby-on-rails ruby-on-rails-3


【解决方案1】:

这适用于 Rails 4

def change
  rename_column :general_exams, :semester, :semester_id
  change_column :general_exams, :semester_id, :integer
end

【讨论】:

    【解决方案2】:

    您的问题可能是semester 包含无法转换为integers 的数据。这就是为什么你会得到一个转换错误。

    我怀疑您需要做更多工作才能完成这项工作,因为唯一想到的就是删除该列并创建一个具有正确值的新列。

    但您可以在一次迁移中简单地删除_column,然后再添加_column。那应该可以完美运行。

    我还建议您先只添加_column,然后执行映射过程,将旧的semester 值映射到新的semester_id,然后删除列。

    请记住,您可以在迁移中进行 ActiveRecord 操作。所以你可以把那个代码放在那里。

    【讨论】:

    • 我销毁了 GeneralExam 表中的所有数据。如果我找不到同时这样做的方法,我将创建 2 个迁移,但我认为这不方便。感谢您的回答。
    • 用更多细节更新了我的答案
    • 我不需要学期专栏的旧数据。所以首先 remove_column 或 add_column 可能不是问题。我会这样做,谢谢。
    【解决方案3】:

    希望对你有帮助

    类 ModifyColumnTables 定义变化 remove_column :posts, :old_column add_column :posts, :new_column, :type_of_column 结尾 结尾

    【讨论】:

      【解决方案4】:

      这个错误是因为表中存在现有数据(或默认值,也许是..),PG 不知道如何从字符串转换为整数。要么删除数据,要么告诉 PG 你想如何转换它,使用 PG 特定的 SQL(我想你会想要 USING)和 execute 迁移命令。请参阅 Rails 迁移指南。

      【讨论】:

      • 我销毁了该表中的所有数据。你的意思是我应该使用 up 和 down?
      • 如果您已经销毁了所有数据,那么我唯一能想到的就是该列可能有一个默认值(无法转换为整数)。我不是 PG 期望的。
      • 我没有为该列设置默认值,我也不明白为什么当列没有值时我不能更改类型。所以我不得不选择另一种方式。大声笑,我也不是任何专家,我仍然只是学生:))
      【解决方案5】:

      您可以通过一次迁移来完成此操作。但这并不总是有效,您可能会遇到错误,尤其是在将列从布尔类型转换为整数类型或将字符串类型转换为整数类型时,除非您具体说明如何转换此数据

      所以您在general_exams 表中有一个名为semester 的列,它是一个字符串。您想将其重命名为 semester_id 并且您想将其类型更改为整数。

      在您执行任何这些操作之前,请确保您已将您的工作提交给 git,以便您始终可以重置为旧提交并重新开始,而不会丢失您的工作。

      在你的终端运行

      rails g migration rename_the_column_semester_to_semester_id
      

      这将为您生成迁移。现在打开您的迁移文件。

      db/migrate/20210xxx_rename_the_column_semester_to_semester_id.rb
      

      看起来像这样:

      class RenameTheColumnSemesterToSemesterID < ActiveRecord::Migration
        def change
        end
      end
      

      在 change 方法中,让你的文件看起来像这样。

      class RenameTheColumnSemesterToSemesterID < ActiveRecord::Migration
        def change
          rename_column :general_exams, :semester, :semester_id
          change_column :general_exams, :semester_id, :integer, using: 'semester_id::integer'
        end
      end
      

      您也可以这样做:

      class RenameTheColumnSemesterToSemesterID < ActiveRecord::Migration
        def change
          rename_column :general_exams, :semester, :semester_id
          change_column :general_exams, :semester_id, 'integer USING CAST(semester_id AS integer)'
        end
      end
      

      注意事项: 仅当您的列在表中没有默认值时,上述方法才有效。这很重要,因为如果您已经为列设置了默认值,您仍然会收到类似PG::DatatypeMismatch: ERROR: default for column "semester_id" cannot be cast automatically to semester integer PG 的错误,因为您的学期列已经有默认值。在这种情况下,您需要在重命名列并设置新的默认值后删除默认值。

      class RenameTheColumnSemesterToSemesterID < ActiveRecord::Migration
        def change
          rename_column :general_exams, :semester, :semester_id
          execute "ALTER TABLE general_exams ALTER semester_id DROP DEFAULT;"
          change_column :general_exams, :semester_id, :integer, using: 'semester_id::integer', default: 1
        end
      end
      

      当然,你可以设置你想要的任何默认值,以防你在你的模型中从 0、1、2 或其他值枚举。

      保存您的迁移。并运行

      rails db:migrate
      

      【讨论】:

        猜你喜欢
        • 2017-07-28
        • 2020-01-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-31
        • 2021-12-04
        • 2019-07-14
        • 2019-09-18
        相关资源
        最近更新 更多