向现有表中添加一个不可为空的列失败。是“价值”属性被忽略? [英] Adding a non-nullable column to existing table fails. Is the "value" attribute being ignored?

查看:179
本文介绍了向现有表中添加一个不可为空的列失败。是“价值”属性被忽略?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景:我们有一个Grails 1.3.7应用程序,并使用Liquibase来管理我们的数据库迁移。



我试图在现有的表格中添加一个新列

我的变更集如下所示: changeSet(author:someCoolGuy(generated),id:1326842592275-1){
addColumn(tableName:layer){
column(name:abstract_trimmed,type:VARCHAR 455),value:No text){
constraints(可空:false)
}
}
}

哪些应该在每个现有行中插入值'没有文本',因此满足非空约束。 Liquibase添加列文档



但是,当正在应用迁移变更集时,我收到以下异常:

  liquibase.exception.DatabaseException:执行SQL ALTER TABLE时出错层添加abstract_trimmed VARCHAR(455)NOT NULL:错误:columnabstract_trimmed包含空值

对我来说,因为它没有使用'value'属性。



如果我将变更集更改为下面的功能,我可以实现同样的功能。但我不想(也不应该)这样做。

  changeSet(author:someCoolGuy(generated ),id:1326842592275-1){
addColumn(tableName:layer){
column(name:abstract_trimmed,type:VARCHAR(455))
}
$ b addNotNullConstraint(tableName:layer,columnName:abstract_trimmed,defaultNullValue:No text)
}

Liquibase是否真的忽略了我的属性,还是还有别的东西在我看不到?



我使用的是Grails 1.3.7,数据库迁移插件1.0,Postgres 9.0

解决方案

简短回答



如果在创建列时添加非空约束,则value属性不起作用未在文档中提及)。生成的SQL将无法执行。



解决方法



问题中描述的解决方法是去。生成的SQL将是:


  1. 添加列

      ALTER TABLE图层ADD COLUMN abstract_trimmed varchar(455); 


  2. 为每行设置一个非空值

      UPDATE table SET abstract_trimmed ='没有文字'; 


  3. 添加NOT NULL约束

      ALTER TABLE图层ALTER COLUMN abstract_trimmed SET NOT NULL; 




为什么?



列缺省值只能用 INSERT 插入到列中。 value标签会为您执行此操作,但在列添加后。 Liquibase尝试在一步中添加列,并使用NOT NULL约束:

  ALTER TABLE图层ADD abstract_trimmed VARCHAR(455 )NOT NULL 

...这是不可能的包含行。它只是不够聪明。

另一种解决方案



自PostgreSQL 8.0(现在几乎永远)另一种方法是使用非空 DEFAULT 子句添加新列:

  ALTER TABLE层ADD COLUMN abstract_trimmed varchar(455)DEFAULT'No text'; 

我引用 ALTER TABLE 的手册:


使用ADD COLUMN添加列时,表
中的所有现有行将使用该列的默认值进行初始化(如果未指定DEFAULT
子句,则为NULL)。



Background: we have a Grails 1.3.7 app and are using Liquibase to manage our database migrations.

I am trying to add a new column to an existing table which is not empty.

My changeset looks like this:

    changeSet(author: "someCoolGuy (generated)", id: "1326842592275-1") {
        addColumn(tableName: "layer") {
            column(name: "abstract_trimmed", type: "VARCHAR(455)", value: "No text") {
                constraints(nullable: "false")
            }
        }
    }

Which should have inserted the value 'No text' into every existing row, and therefore satisfied the not null constraint. Liquibase "Add Column" docs.

But when the migrations changesets are being applied I get the following exception:

liquibase.exception.DatabaseException: Error executing SQL ALTER TABLE layer ADD abstract_trimmed VARCHAR(455) NOT NULL: ERROR: column "abstract_trimmed" contains null values

Which looks to me like it is not using the 'value' attribute.

If I change my changeset to work look like the following I can achieve the same thing. But I don't want to (and shouldn't have to) do this.

    changeSet(author: "someCoolGuy (generated)", id: "1326842592275-1") {
        addColumn(tableName: "layer") {
            column(name: "abstract_trimmed", type: "VARCHAR(455)")
        }

        addNotNullConstraint(tableName: "layer", columnName:"abstract_trimmed", defaultNullValue: "No text")
    }

Is Liquibase really ignoring my value attribute, or is there something else going on here that I can't see?

I am using Grails 1.3.7, Database-migration plugin 1.0, Postgres 9.0

解决方案

Short answer

The "value" attribute will not work if you are adding a not-null constraint at the time of the column creation (this is not mentioned in the documentation). The SQL generated will not be able to execute.

Workaround

The workaround described in the question is the way to go. The resulting SQL will be:

  1. Add the column

    ALTER TABLE layer ADD COLUMN abstract_trimmed varchar(455);
    

  2. Set it to a non-null value for every row

    UPDATE table SET abstract_trimmed = 'No text';
    

  3. Add the NOT NULL constraint

    ALTER TABLE layer ALTER COLUMN abstract_trimmed SET NOT NULL;
    

Why?

A column default is only inserted into the column with an INSERT. The "value" tag will do that for you, but after the column is added. Liquibase tries to add the column in one step, with the NOT NULL constraint in place:

ALTER TABLE layer ADD abstract_trimmed VARCHAR(455) NOT NULL

... which is not possible when the table already contains rows. It just is not smart enough.

Alternative solution

Since PostgreSQL 8.0 (so almost forever by now) an alternative would be to add the new column with a non-null DEFAULT clause:

ALTER TABLE layer ADD COLUMN abstract_trimmed varchar(455) DEFAULT 'No text';

I quote the manual on ALTER TABLE:

When a column is added with ADD COLUMN, all existing rows in the table are initialized with the column's default value (NULL if no DEFAULT clause is specified).

这篇关于向现有表中添加一个不可为空的列失败。是“价值”属性被忽略?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆