我需要为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
答案 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