2012-04-27 79 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 
相關問題