Rails迁移更改列以使用Postgres数组

时间:2014-03-21 04:18:43

标签: ruby-on-rails ruby postgresql migration

我正在尝试更改数据库中的列,以便它可以使用Postgres数组数据类型。 目前,表列的类型为字符串。

我正在使用以下迁移来转换它:

def change
  change_column :table, :dummy_column, :text, array: true, default: []
end

但是我收到以下错误:

bundle exec rake db:migrate
rake aborted!
An error has occurred, this and all later migrations canceled:

PG::Error: ERROR:  column "dummy_column" cannot be cast automatically to type     character varying[]
HINT:  Specify a USING expression to perform the conversion.
: ALTER TABLE "table" ALTER COLUMN "dummy_column" TYPE character varying(255) 
Tasks: TOP => db:migrate

5 个答案:

答案 0 :(得分:28)

PostgreSQL不知道如何自动将varchar列转换为varchar数组。它不知道您可能想要什么,因为它无法知道您认为当前值的格式。

所以你需要告诉它;这就是USING子句的用途。

ActiveRecord似乎没有显式支持USING子句(这并不奇怪,因为它几乎不支持最基本的数据库功能)。但是,您可以为迁移指定自己的SQL文本。

假设您的字符串以逗号分隔,并且可能不包含逗号,例如:

def change
  change_column :table, :dummy_column, "varchar[] USING (string_to_array(dummy_column, ','))"
end

(我自己并没有使用Rails,也没有对此进行测试,但它与其他地方的示例中使用的语法一致。)

答案 1 :(得分:13)

在postgresql 9.4上使用Rails 4.2我希望这样做并保留我原有的字符串数据作为一个元素数组中的第一个元素。

事实证明,如果没有USING表达式,postgresql不能将字符串强制转换为文本数组,以告诉它如何。

经过精心设计的postgres语法后,我发现了一个很好的中间路线,有活跃的记录:

def change
  change_column :users, :event_location, :text, array: true, default: [], using: "(string_to_array(event_location, ','))"
end

唯一的直接postgresql有(string_to_array() )函数调用。 Here are the docs on that - 请注意,您必须提供分隔符。

答案 2 :(得分:3)

在postgresql 9.4上使用Rails 4.2,使用向下和向上,基于lrrthomas响应。 注意:您的起始列的默认值为nil

class ChangeEmailAndNumberColumnForContact < ActiveRecord::Migration
  def up
    change_column :contacts, :mobile_number, :text, array: true, default: [], using: "(string_to_array(mobile_number, ','))"
    change_column :contacts, :email, :text, array: true, default: [], using: "(string_to_array(email, ','))"
  end

  def down
    change_column :contacts, :mobile_number, :text, array: false, default: nil, using: "(array_to_string(mobile_number, ','))"
    change_column :contacts, :email, :text, array: false, default: nil, using: "(array_to_string(email, ','))"
  end
end

答案 3 :(得分:2)

def change

    change_column :table, :dummy_column, :string, array: true, default: '{}'

end

注意:

它被指定为数据类型:string with array:true默认列为空数组([]),使用默认值:'{}'

答案 4 :(得分:1)

可以通过以下方式完成:

microbenchmark