【问题标题】:How do I change a string column into a bigint?如何将字符串列更改为 bigint?
【发布时间】:2012-05-09 23:00:43
【问题描述】:

在 Rails 迁移中。如何将字符串类型的列更改为 bigint?

我有:

t.change :ip_number_from, :integer, :limit => 8

我明白了:

PG::Error: ERROR:  column "ip_number_from" cannot be cast to type bigint

我什至尝试了两种选择:

change_column :ip_to_countries, :ip_number_from, :integer, :limit => 8
change_column :ip_to_countries, :ip_number_from, :bigint

还是同样的错误。

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 postgresql heroku migration


    【解决方案1】:

    Postgres 告诉您该列中存在它不知道如何转换的现有数据,因此它需要一个 ALTER 语句,该语句为该列提供一个 USING 子句来指定如何转换现有值。

    不幸的是,您将需要下拉特定于数据库的代码来完成此操作,或者使用类似于此处建议的解决方案的方法:

    http://webjazz.blogspot.co.uk/2010/03/how-to-alter-columns-in-postgresql.html

    编辑:您可以在迁移中直接在 SQL 中执行此操作:

    execute <<-SQL
      ALTER TABLE ip_to_countries
      ALTER COLUMN ip_number_from TYPE bigint USING ip_number_from::bigint
    SQL
    

    【讨论】:

    • 在迁移文件中,这也有效:IpToCountry.connection.execute('alter table ip_to_countries alter ip_number_from type bigint using ip_number_from::bigint;')
    【解决方案2】:

    您的 ip_number_from 列中有什么内容?

    无论如何,我可能会:

    • 新建一个 bigint 类型的列,
    • 通过 rails 控制台或 rake 任务手动将数据从 ip_number_from 复制到 new_column,
    • 删除原始 ip_number_from 列
    • 将 new_column 重命名为 ip_number_from

    或者您可以像 mjtko 建议的那样使用 SQL,但我不确定它是否会更容易。

    更新

    我查看了 Yule 的建议。我认为在一次迁移中完成所有这些操作会有点危险,因为您无法真正检查数据的转换/复制是否成功。如果您确实想在一次迁移中执行此操作,那么在您的情况下,它看起来像这样:

    def up
      add_column :table, :new_column, :bigint
      Model.reset_column_information
      Model.all.each do |m|
        m.update_attribute :new_column, Model.bigint_from_ip_number_from(m)
      end
      drop_column :table, :ip_number_from
      rename_column :table, :new_column, :ip_number_from
    end
    

    您还应该添加相应的向下迁移。

    您始终可以将其拆分为多个迁移,并随时检查进度/成功。

    【讨论】:

    • 如果你采用这种方法,我会把它放在迁移中,而不是控制台/其他 rake 任务中。如果要从迁移中创建数据库,则需要保持一致
    • 如果您的目标是完全独立于数据库,这是一种明智的方法,但恕我直言,这不是最有效的解决方案。
    • 我同意这不是最有效的方法。如果 ip_number_from 中有一个类似“foobar”的字符串,你知道你的迁移会发生什么吗?我真的很好奇,我不知道。它只是失败并回滚吗?还是新的 ip_number_from 为空?
    • 谢谢,我发现这种方法是最易于维护的,因为如果您直接在数据库中执行 SQL,您会丢失迁移历史记录,并且永远必须记住在 SQL 控制台中进行这一调整。花时间进行良好的迁移可确保生产环境和同事环境的连续性和经过测试的修复。
    【解决方案3】:

    我最近读到——但不记得在哪里——你不能将“string”列转换为“int”列,但你可以做相反的事情。从“int”到“string”的转换是不可逆的迁移操作。

    我将搜索我阅读该文章的文档,并在找到它时编辑我的帖子。

    如果可以,最简单的做法就是按照 Jure Triglav 的建议。 (他在我之前发布了他的答案,但我提出了同样的建议;))。

    [编辑] 我找到了我读到的地方:Irreversible Migration tuto

    【讨论】:

    • 无法从字符串转换为整数并非所有 DBMS 都如此,我认为那篇文章只是以这种操作为例。 :)
    【解决方案4】:

    change_column :table_name, :column_name, 'TYPE bigint USING CAST(column_name AS TYPE bigint)'

    【讨论】:

      猜你喜欢
      • 2010-12-18
      • 2015-10-24
      • 2021-01-08
      • 2015-06-02
      • 1970-01-01
      • 2014-12-27
      • 2016-08-18
      • 2018-07-14
      • 2010-12-21
      相关资源
      最近更新 更多