Вопрос по ruby-on-rails, postgresql, ruby – Rails Migrations: попытался изменить тип столбца со строки на целое число

30

Я создал таблицу в своем приложении rails с помощью команды rails generate migrations. Вот этот файл миграции:

<code>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
</code>

Затем я хотел сохранить широту и долготу как целые числа, так Я пытался бежать:

<code>rails generate migration changeColumnType
</code>

и содержимое этого файла:

<code>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
</code>

Я ожидал, что тип столбца изменится, однако грабли были прерваны, и появилось следующее сообщение об ошибке. Мне было интересно, почему это не прошло? Я использую postgresql в моем приложении.

<code>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)
</code>

ПРИМЕЧАНИЕ. В таблице нет данных. Спасибо

Если данных нет, вы можете просто удалить столбцы и добавить их с правильным типом. Целая степень широты и долготы довольно велика, поэтому вы можете подумать о том, какой тип вы хотите использовать для этих столбцов. mu is too short
Убедитесь, что у вас нет данных, и попробуйте сделать откат Ismael Abreu

Ваш Ответ

6   ответов
23

около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;

Это работает с данными или без данных до тех пор, пока все записи конвертируются вinteger.
Если вы определилиDEFAULT для столбца, вам, возможно, придется удалить и заново создать его для нового типа.

Вотblog статья о том, как сделать это с ActiveRecord.
Или следуйте совету @ му в комментарии. Он знает свой Рубин. Я только хорошо с PostgreSQL здесь.

Для решения проблемы миграции рельсов, пожалуйста, посмотрите здесь: / Stackoverflow.com вопросы / 10690289 / ... cintrzyk
Для одного раза проще всего обернуть SQL вconnection.execute('...') Скорее дурачится обезьянами. mu is too short
21

это немного уродливо, но я предпочитаю просто удалить столбец и добавить еще раз с новым типом:

 def change
     remove_column :mytable, :mycolumn
     add_column :mytable, :mycolumn, :integer, default: 0
 end
Я запустил миграцию change_column: mytable,: mycolumn,: float. Затем запустил еще пару миграций, подтолкнул к github, толкнул к героку только для того, чтобы получить эту ошибку. Я запустил новую миграцию, как вы предложили выше, но ошибка все еще сохраняется из-за предыдущей миграции. Теперь я не могу откатиться, потому что remove_column необратим. Я фубар? tomb
после нескольких часов попыток это помогло мне преобразовать логическое значение в enum Jose Kj
Обновление предыдущего комментария: я удалил предыдущую миграцию с помощью 'rails destroy migration_name', затем rake db: migrate, и теперь все в порядке. tomb
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
21

как показано ниже, чтобы он обновлял 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
Обратите внимание, что нижний ALTER должен быть varchar вместо текста, чтобы соответствовать типу строки. Martin
10

Следующее является болееrails way подходить к проблеме. В моем случае в моей таблице покупок было два столбца, которые мне нужно было преобразовать из типа string в float.

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

Это помогло мне.

Это отлично сработало, спасибо. Paul Watson
2
У вас есть данные в этих столбцах? Вы не должны использовать int для широты и долготы. Вместо этого они должны быть с плавающей точкой.
Использование целого или длинного в (например) градусах * 10 ^ 12 широты / долготы может быть намного быстрее и эффективнее при хранении, если вы заранее знаете необходимое разрешение. Тем не менее, PITA может работать с ошибками преобразования, если все ваши алгоритмы не могут работать с ним в этой форме. Я согласен, что double или float безопаснее, если вы не знаете, что вам нужно что-то другое и у вас есть на то веские причины. Craig Ringer
Вот объяснение и рекомендация Google Maps: Developers.google.com / карты / Статьи / phpsqlajax # CreateTable Victor
Что плохого в том, чтобы хранить их как строки? banditKing

Похожие вопросы