2012-04-27 77 views
24

我在rails应用程序中使用rails generate migrations命令创建了一个表。下面是迁移文件:Rails 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 

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

rails generate migration changeColumnType 

和该文件的内容是:

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 

我期待列类型改变,但耙子被中止,并出现以下错误消息。我想知道为什么这没有通过?我在我的应用程序中使用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) 

注意:该表没有数据。 感谢

+0

确保您有它没有数据,你可以尝试做一回退 – 2012-04-27 01:03:16

+3

如果没有数据可以直接删除列,并将它们与正确类型重新添加。经纬度的整体度非常大,所以您可能想要考虑这些列真正需要的类型。 – 2012-04-27 01:36:08

回答

23

我引用手动about ALTER TABLE

如果从旧的隐式或分配 铸造新的类型必须提供使用条款。

你需要的是:

 
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; 

作品有或没有数据只要所有条目可转换为integer
如果您已经为列定义了DEFAULT,则可能必须删除并重新创建新类型。

这里是blog article on how to do this with ActiveRecord
或者在评论中发表@ mu的建议。他知道他的Ruby。我在这里只使用PostgreSQL。

+4

对于一次性,最简单的做法是将SQL包装在'connection.execute('...')'中,而不是用猴子修补程序。 – 2012-04-27 01:36:30

+1

对于rails迁移解决方案,请看看这里:http://stackoverflow.com/questions/10690289/rails-gmaps4rails-gem-on-postgres – cintrzyk 2013-09-23 14:02:31

2
  1. 您是否有这些列中的现有数据?
  2. 您不应该在经度和纬度上使用int。它们应该处于浮点状态。
+0

使用整数或长(例如)度* 10^12的拉特如果您事先知道您需要的分辨率,long可以更快,更高效地存储。 PITA可以使用,但很容易出现转换错误,除非您的所有算法都可以在本机上以该形式工作。我同意double或float更安全,除非你知道你需要不同的东西并且有很好的理由。 – 2012-04-27 04:20:33

+0

将它们存储为字符串有什么问题? – banditKing 2012-04-27 07:06:30

+0

以下是Google地图的说明和建议:https://developers.google.com/maps/articles/phpsqlajax#createtable – Victor 2012-04-27 11:34:27

21

我会在下面的迁移文件中包含原始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 
+0

请注意,向下ALTER应该是varchar而不是文本以匹配字符串类型。 – Martin 2014-06-23 20:04:30

17

我知道这有点难看,但我更愿意只删除列,并与新型再次添加:

def change 
    remove_column :mytable, :mycolumn 
    add_column :mytable, :mycolumn, :integer, default: 0 
end 
+0

我运行了一个迁移change_column:mytable,:mycolumn,:float。然后跑了几次迁徙,推到github,推到heroku才得到这个错误。我按照上面的建议运行了新的迁移,但由于之前的迁移,错误仍然存​​在。现在我不能回滚,因为remove_column是不可逆的。我是fubar吗? – tbone 2018-02-06 19:07:53

+0

更新到之前的评论:我删除了先前使用'rails destroy migration migration_name'进行的迁移,然后使用rake db:migrate,现在一切正常。 – tbone 2018-02-06 19:46:30

7

下面是一个更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 

这对我来说是诀窍。

+0

这对我很好,谢谢。 – 2016-08-22 22:57:16

0

纬度和经度小数

rails g scaffold client name:string email:string 'latitude:decimal{12,3}' 'longitude:decimal{12,3}' 

class CreateClients < ActiveRecord::Migration[5.0] 
    def change 
    create_table :clients do |t| 
     t.string :name 
     t.string :email 
     t.decimal :latitude, precision: 12, scale: 3 
     t.decimal :longitude, precision: 12, scale: 3 

     t.timestamps 
    end 
    end 
end 
相关问题