背景:我们有一个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")
}
}
}
哪个应该在每个现有行中插入值'No text',因此满足not null约束。 Liquibase "Add Column" docs
但是当应用迁移变更集时,我得到以下异常:
liquibase.exception.DatabaseException: Error executing SQL ALTER TABLE layer ADD abstract_trimmed VARCHAR(455) NOT NULL: ERROR: column "abstract_trimmed" contains null values
在我看来,它并没有使用'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")
}
Liquibase是否真的忽略了我的value
属性,或者还有其他一些我无法看到的内容?
我正在使用Grails 1.3.7,数据库迁移插件1.0,Postgres 9.0
答案 0 :(得分:16)
如果在创建列时添加非空约束,则“value”属性将不起作用(documentation中未提及)。生成的SQL将无法执行。
问题中描述的解决方法是要走的路。生成的SQL将是:
添加列
ALTER TABLE layer ADD COLUMN abstract_trimmed varchar(455);
将其设置为每行的非空值
UPDATE table SET abstract_trimmed = 'No text';
添加NOT NULL约束
ALTER TABLE layer ALTER COLUMN abstract_trimmed SET NOT NULL;
列默认值仅插入到INSERT
的列中。 “value”标记会为您执行此操作,但 后会添加该列。 Liquibase尝试在一步中添加列,并NOT NULL
约束:
ALTER TABLE layer ADD abstract_trimmed VARCHAR(455) NOT NULL;
当表已经包含行时,... 不可能。它只是不够聪明。
自PostgreSQL 8.0(现在几乎是永远)以来,另一种方法是使用非空 DEFAULT
子句添加新列:
ALTER TABLE layer ADD COLUMN abstract_trimmed varchar(455) DEFAULT 'No text';
使用
ADD COLUMN
添加列时,表中的所有现有行 使用列的默认值初始化(如果没有DEFAULT
则为NULL 指定的子句)。
答案 1 :(得分:1)
使用“defaultValue”而不是“value”来设置新列的默认值。
答案 2 :(得分:0)
分两个步骤进行操作:
changeSet(author: "someCoolGuy (generated)", id: "1326842592275-1") {
addColumn(tableName: "layer") {
column(name: "abstract_trimmed", type: "VARCHAR(455)", defaultValue: "No text") {
constraints(nullable: "false")
}
}
}
changeSet(author: "someCoolGuy (generated)", id: "1326842592275-2") {
dropDefaultValue(tableName: "layer" columnName: "abstract_trimmed")
}
这样做的一个好处是,如果您要在列中输入一个非静态值,它将对其进行一次计算并将其用于填充所有现有行(例如:时间戳),而不是可能每次行更改时都要重新计算。