Postgresql无法更改列的数据类型

时间:2016-05-20 10:26:30

标签: sql database postgresql

我是Postgresql的新手,我正在尝试从Integer to Varchar(20)更改列的数据类型,但我得到了一个奇怪的错误:

   ERROR:  operator does not exist: character varying <> integer :
      No operator matches the given name and argument type(s). 
    You might need to add explicit type casts.********** Error **********

我写的用于创建表的脚本是:

CREATE TABLE LOGIN(
USERNAME INTEGER NOT NULL CHECK(USERNAME != NULL),
PASSWORD VARCHAR(10) NOT NULL CHECK(PASSWORD <>'' AND USERNAME != NULL)
);

这是我用来修改从Integer到Varchar的列的脚本:

ALTER TABLE LOGIN ALTER COLUMN USERNAME TYPE varchar(20);

我感谢任何帮助。感谢。

3 个答案:

答案 0 :(得分:2)

使用USING expression。它允许您定义值转换:

ALTER TABLE LOGIN ALTER COLUMN USERNAME TYPE varchar(20) USING ...expression...;

来自PostgreSQL documentation

  

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

答案 1 :(得分:0)

问题出在USERNAME的CHECK约束中。您可以使用目录pg_constraint以某种方式找到解决方法:

SELECT conname, consrc
  FROM pg_constraint
 WHERE conrelid =
    (SELECT oid
       FROM pg_class
      WHERE relname LIKE 'login');

在字段'consrc'中,您可能会注意到约束实际上看起来像“(用户名&lt;&gt; NULL :: integer)”,并且当您尝试将列类型从整数更改为varchar时会出现错误。

要删除约束,请使用

ALTER TABLE LOGIN DROP CONSTRAINT login_username_check;
ALTER TABLE LOGIN DROP CONSTRAINT login_check;

其中'login_username_check'和'login_check'是您从上面的查询得到的同名(小心并仔细检查这些名称)。

之后你应该尝试

ALTER TABLE LOGIN ALTER COLUMN USERNAME TYPE varchar(20);

如果您的表中没有数据,这应该有效。如果没有,请添加

ALTER TABLE dev.tests_LOGIN ALTER COLUMN USERNAME TYPE varchar(20) USING USERNAME::VARCHAR;

您可能想要恢复PASSWORD&lt;&gt;''检查,因此您必须再做一次更改才能恢复它。祝你好运!

您可能会发现一些方便的PostgreSQL文档:

pg_constraint doc

alter doc

PS:如上所述,当列描述中已经有NOT NULL时,您不需要检查约束(!= NULL)。此外,NULL检查有点不同。快速说明:

SELECT (NULL = NULL);
SELECT (NULL != NULL);
SELECT (NULL IS NULL);
SELECT (NULL IS NOT NULL);

答案 2 :(得分:0)

错误的原因是您拥有无用的额外检查约束(<> null):

  

运算符不存在:字符变化&lt;&gt;整数:

指的是两个检查约束中的条件USERNAME != NULL

(SQL中的&#34; not equals&#34;运算符为<>,并且!=被重写为){/ p>

所以你首先需要摆脱那些检查约束。该检查的默认生成名称为login_username_check,因此以下内容最有效:

alter table login 
   drop constraint login_username_check;

另一项检查很可能是login_check

alter table login 
   drop constraint login_check;

删除这些检查约束后,您可以更改数据类型:

ALTER TABLE LOGIN 
    ALTER COLUMN USERNAME set data TYPE varchar(20);

现在您需要重新添加密码约束:

alter table login 
    add constraint check_password check (password <> '');

如果由于某种原因生成的约束名称与我假设的约束名称不同,您可以使用以下命令找到名称:

select c.conname, c.consrc
from pg_constraint c
  join pg_class t on c.conrelid = t.oid
  join pg_namespace n on t.relnamespace = n.oid
where t.relname = 'login'
  and n.nspname = 'public'; --<< change here for the correct schema name

正如jarlh已经评论过的那样,将列定义为NOT NULL就足够了。没有必要添加另一个&#34; not null&#34;校验。另外:检查错了。您无法使用null=将值与<>进行比较。要测试非空值,您需要使用IS NOT NULL。编写显式检查约束的正确方法是

 username check (username is not null)