25

在我的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 表中,我销毁了所有数据。那么,任何人都可以告诉我我该怎么做?或者我必须创建两个迁移文件?

4

5 回答 5

19

这适用于 Rails 4

def change
  rename_column :general_exams, :semester, :semester_id
  change_column :general_exams, :semester_id, :integer
end
于 2015-05-26T08:57:26.730 回答
12

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

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

但是您可以在一次迁移中简单地 remove_column 然后 add_column。那应该完美无缺。

我还建议您先仅 add_column,然后执行映射过程,将旧semester值映射到新值semester_id,然后删除列。

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

于 2012-11-20T10:02:18.297 回答
1

我希望这有帮助

类 ModifyColumnTables
  定义变化
    remove_column :posts, :old_column
    add_column :posts, :new_column, :type_of_column
  结尾
结尾
于 2018-02-11T02:36:59.337 回答
0

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

于 2012-11-20T10:06:15.507 回答
0

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

所以你在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

在更改方法中,使您的文件看起来像这样。

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 integerPG 会抱怨您的学期列已经有默认值。在这种情况下,您需要在重命名列并设置新的默认值后删除默认值。

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
于 2021-04-18T22:57:25.397 回答