Rails迁移:尝试将列的类型从字符串更改为整数

ban*_*ing 30 ruby postgresql casting ruby-on-rails rails-migrations

我在rails应用程序中使用rails generate migrations命令创建了一个表.这是迁移文件:

class CreateListings < ActiveRecord::Migration
  def change
    create_table :listings do |t|
      t.string :name
      t.string :telephone
      t.string :latitude
      t.string :longitude

      t.timestamps
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

然后我想将纬度和经度存储为整数,所以我试图运行:

rails generate migration changeColumnType
Run Code Online (Sandbox Code Playgroud)

并且该文件的内容是:

class ChangeColumnType < ActiveRecord::Migration
  def up
    #change latitude columntype from string to integertype
    change_column :listings, :latitude, :integer
    change_column :listings, :longitude, :integer
    #change longitude columntype from string to integer type
  end

  def down  
  end
end
Run Code Online (Sandbox Code Playgroud)

我期待列类型改变但是rake被中止并且出现以下错误消息.我想知道为什么这不通过?我在我的应用程序中使用postgresql.

rake db:migrate
==  ChangeColumnType: migrating ===============================================
-- change_column(:listings, :latitude, :integer)
rake aborted!
An error has occurred, this and all later migrations canceled:

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

Tasks: TOP => db:migrate
(See full trace by running task with --trace)
Run Code Online (Sandbox Code Playgroud)

注意:该表没有DATA.谢谢

Erw*_*ter 25

我引用手动ALTER TABLE:

如果没有从旧类型到新类型的隐式或赋值转换,则必须提供USING子句.

你需要的是:

ALTER TABLE listings ALTER longitude TYPE integer USING longitude::int;
ALTER TABLE listings ALTER latitude  TYPE integer USING latitude::int;

或者在一个命令中更短更快(对于大表):

ALTER TABLE listings ALTER longitude TYPE integer USING longitude::int
                    ,ALTER latitude  TYPE integer USING latitude::int;
Run Code Online (Sandbox Code Playgroud)

这个工作有或没有数据,只要所有项目均转换为integer.
如果已DEFAULT为列定义了a ,则可能必须删除并为新类型重新创建该列.

这是关于如何使用ActiveRecord执行此操作的博客文章.
或者在评论中使用@ mu的建议.他知道他的Ruby.我在这里只对PostgreSQL很好.

  • 对于一次性,最简单的方法是将SQL包装在`connection.execute('...')中,而不是用猴子修补. (4认同)

nev*_*asy 23

我会在您的迁移文件中包含原始SQL,如下所示,以便更新schema.rb.

class ChangeColumnType < ActiveRecord::Migration
  def up
    execute 'ALTER TABLE listings ALTER COLUMN latitude TYPE integer USING (latitude::integer)'
    execute 'ALTER TABLE listings ALTER COLUMN longitude TYPE integer USING (longitude::integer)'
  end

  def down
    execute 'ALTER TABLE listings ALTER COLUMN latitude TYPE text USING (latitude::text)'
    execute 'ALTER TABLE listings ALTER COLUMN longitude TYPE text USING (longitude::text)'
  end
end
Run Code Online (Sandbox Code Playgroud)


riz*_*oro 21

我知道这有点难看,但我更喜欢删除列并再次添加新类型:

 def change
     remove_column :mytable, :mycolumn
     add_column :mytable, :mycolumn, :integer, default: 0
 end
Run Code Online (Sandbox Code Playgroud)


Jos*_* N. 11

以下是rails way解决问题的方法.对于我的情况,我在购买表中有两列我需要从类型字符串转换为浮点数.

def change
    change_column :purchases, :mc_gross, 'float USING CAST(mc_gross AS float)'
    change_column :purchases, :mc_fee, 'float USING CAST(mc_fee AS float)'
end
Run Code Online (Sandbox Code Playgroud)

这对我有用.