无法使用转换迁移PostgreSQL Alter Table

时间:2013-10-25 07:59:10

标签: ruby-on-rails postgresql

我需要为rails应用程序迁移PG数据库 - 我正在将表的一列类型从boolean更新为int。这是代码:

class ChangeAdminToInt < ActiveRecord::Migration
  def up
    execute '
      ALTER TABLE "users"
      ALTER COLUMN "admin"
      TYPE int USING ("admin"::int)
      SET DEFAULT "1"
      '
  end
end

当我运行bundle exec rake db:migrate时,我收到错误:

PG::Error: ERROR:  syntax error at or near "SET"
LINE 5:  SET DEFAULT "1"

但是当我将代码切换到:

class ChangeAdminToInt < ActiveRecord::Migration
  def up
    execute '
      ALTER TABLE users 
      ALTER COLUMN admin 
      TYPE int USING (admin::int);
      SET DEFAULT 1
      '
  end
end

我收到错误:

PG::Error: ERROR:  syntax error at or near "TYPE"
LINE 5:  TYPE int USING ("admin"::int)

因为问题不在于函数,而是在第5行,我认为数据库只是不喜欢第5行。引用长度是否限制PG只解析部分执行命令?我已经尝试了许多类型的语法,单/双引号,%q /%Q块,甚至将整个引用放在一行,但语法错误仍然指向TYPE和SET DEFAULT的早期版本。当然问题不在于ALTER这里发生了什么?

感谢任何帮助。如果我错过了一些完全明显的东西,请告诉我BTW一些​​Gemfile:

source 'https://rubygems.org'
ruby '1.9.3'

gem 'rails', '~> 4.0.1.rc3'
gem 'bootstrap-sass', '2.3.2.0'
gem 'bcrypt-ruby', '~> 3.1.1'
gem 'faker', '1.1.2'
gem 'will_paginate', '3.0.4'
gem 'bootstrap-will_paginate', '0.0.9'
gem 'safe_attributes'

group :development, :test do
  gem 'pg', '0.15.1'
  gem 'sqlite3'
  gem 'rspec-rails', '2.13.1'
  gem 'guard-rspec', '2.5.0'
  gem 'spork-rails', github: 'sporkrb/spork-rails'
  gem 'guard-spork', '1.5.0'
  gem 'childprocess', '0.3.6'
end

开发环境的database.yml:

development:
  adapter: postgresql
  encoding: utf8
  database: project_development
  pool: 5
  username: postgres

2 个答案:

答案 0 :(得分:1)

我明白了!

引用PostgreSQL网站http://www.postgresql.org/docs/8.1/static/sql-altertable.html

  

由于这种灵活性,USING表达式不适用于   列的默认值(如果有);结果可能不是   默认值所需的常量表达式。这意味着什么时候   没有从旧类型到新类型的隐式或赋值转换,ALTER   即使USING子句,TYPE也可能无法转换默认值   提供。在这种情况下,使用DROP DEFAULT删除默认值,执行   ALTER TYPE,然后使用SET DEFAULT添加一个合适的新   默认。类似的考虑适用于索引和约束   涉及该栏目。

如果我首先尝试更改类型,则不喜欢旧的默认值。如果我首先设置一个新的默认值,它不知道如何键入转换。本文说,执行特定操作的正确方法是首先删除默认值,更改类型然后设置新的默认值

这是适用于我的代码。

class ChangeAdminToInt < ActiveRecord::Migration
  def up
    execute %q(
      ALTER TABLE users 
      ALTER COLUMN admin DROP DEFAULT,
      ALTER COLUMN admin TYPE int USING ("admin"::int),
      ALTER COLUMN admin SET DEFAULT 1;
      )
  end
end

就是这样!

答案 1 :(得分:0)

我认为您的USING条款不对。这是来自postgre文档(http://www.postgresql.org/docs/8.0/static/sql-altertable.html):

  

可选的USING子句指定如何从旧的计算新列值;如果省略,则默认转换与从旧数据类型转换为new的赋值相同。如果没有从旧类型到新类型的隐式或赋值转换,则必须提供USING子句。

因此,USING用于告诉postgres如何从旧值计算新的值类型。我真的不明白你的查询中USING ("admin"::int)的含义。尝试省略USING子句或尝试这样的事情:

USING CASE WHEN "admin" = TRUE THEN 1 ELSE 0 END