将不可为空的列添加到现有表失败."值"属性是否被忽略?

Dav*_*vid 10 sql postgresql grails database-design liquibase

背景:我们有一个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(nullable: "false")
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

哪个应该在每个现有行中插入值'No text',因此满足not null约束.Liquibase"添加列"文档.

但是当应用迁移更改集时,我得到以下异常:

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

在我看来,它不使用'value'属性.

如果我将变更集更改为工作,如下所示我可以实现相同的目标.但我不想(也不应该)这样做.

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

Liquibase真的忽略了我的value属性,还是还有其他东西在我身上看不到?

我正在使用Grails 1.3.7,Database-migration插件1.0,Postgres 9.0

Erw*_*ter 17

简短的回答

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

解决方法

问题中描述的解决方法是要走的路.生成的SQL将是:

  1. 添加列

    ALTER TABLE layer ADD COLUMN abstract_trimmed varchar(455);
    
    Run Code Online (Sandbox Code Playgroud)
  2. 将其设置为每行的非空值

    UPDATE table SET abstract_trimmed = 'No text';
    
    Run Code Online (Sandbox Code Playgroud)
  3. 添加NOT NULL约束

    ALTER TABLE layer ALTER COLUMN abstract_trimmed SET NOT NULL;
    
    Run Code Online (Sandbox Code Playgroud)

为什么?

列默认值仅插入到列中INSERT."value"标记将为您执行此操作,但添加列之后.Liquibase尝试在一个步骤中添加列,并使用NOT NULL约束:

ALTER TABLE layer ADD abstract_trimmed VARCHAR(455) NOT NULL;
Run Code Online (Sandbox Code Playgroud)

... 当表已包含行时,这是不可能的.它不够聪明.

替代方案

从PostgreSQL 8.0开始(现在几乎是永远),另一种方法是使用非null DEFAULT子句添加新列:

ALTER TABLE layer ADD COLUMN abstract_trimmed varchar(455) DEFAULT 'No text';
Run Code Online (Sandbox Code Playgroud)

手册ALTER TABLE:

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

  • 只是想提一下,问题解决方案中提供的解决方案适用于MySQL,而不适用于MS SQL,因为它很容易理解 - 问题 - Postgres. (2认同)