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

rii*_*rii 15 ruby migration postgresql ruby-on-rails

我试图更改我的数据库中的列,以便它可以使用Postgres数组数据类型.目前,表列的类型为string.

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

def change
  change_column :table, :dummy_column, :text, array: true, default: []
end
Run Code Online (Sandbox Code Playgroud)

但是我收到以下错误:

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
Run Code Online (Sandbox Code Playgroud)

Cra*_*ger 29

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

所以你需要告诉它; 这是该USING条款的用途.

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

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

def change
  change_column :table, :dummy_column, "varchar[] USING (string_to_array(dummy_column, ','))"
end
Run Code Online (Sandbox Code Playgroud)

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


小智 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
Run Code Online (Sandbox Code Playgroud)

唯一的直接postgresql有(string_to_array() )函数调用.以下是关于该文档的文档 -您必须提供分隔符.


tol*_*ard 5

基于 lrrthomas 响应,在 postgresql 9.4 上使用 Rails 4.2 并带有向下和向上。注意:你的起始列应该有一个默认值 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
Run Code Online (Sandbox Code Playgroud)