Sql 将不可为空的列添加到现有表失败。是",;“价值”;属性被忽略?
背景:我们有一个Grails1.3.7应用程序,正在使用Liquibase来管理我们的数据库迁移 我正在尝试向现有表中添加一个非空的新列 我的变更集如下所示:Sql 将不可为空的列添加到现有表失败。是",;“价值”;属性被忽略?,sql,postgresql,grails,database-design,liquibase,Sql,Postgresql,Grails,Database Design,Liquibase,背景:我们有一个Grails1.3.7应用程序,正在使用Liquibase来管理我们的数据库迁移 我正在尝试向现有表中添加一个非空的新列 我的变更集如下所示: changeSet(author: "someCoolGuy (generated)", id: "1326842592275-1") { addColumn(tableName: "layer") { column(name: "abstract_trimmed", type: "VARC
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.exception.DatabaseException: Error executing SQL ALTER TABLE layer ADD abstract_trimmed VARCHAR(455) NOT NULL: ERROR: column "abstract_trimmed" contains null values
在我看来,它没有使用“value”属性
如果我将我的变更集更改为工作,如下所示,我可以实现同样的效果。但我不想(也不应该)这样做
Liquibase真的忽略了我的值
属性吗,还是这里发生了一些我看不到的事情
我正在使用Grails1.3.7、数据库迁移插件1.0、Postgres9.0
如果在创建列时添加NOTNULL约束,“value”属性将不起作用(中未提及)。生成的SQL将无法执行
变通办法
问题中描述的解决方法是可行的。生成的SQL将是:
ALTER TABLE layer ADD COLUMN abstract_trimmed varchar(455);
UPDATE table SET abstract_trimmed = 'No text';
ALTER TABLE layer ALTER COLUMN abstract_trimmed SET NOT NULL;
INSERT
的列中。“value”标记将为您完成此操作,但在添加列之后。Liquibase尝试一步添加列,并使用notnull
约束:
ALTER TABLE layer ADD abstract_trimmed VARCHAR(455) NOT NULL;
。。。当表格已经包含行时,不可能。它只是不够聪明
替代解决方案
由于PostgreSQL 8.0(现在几乎永远如此),另一种选择是添加带有非空默认值的新列:
ALTER TABLE layer
ADD COLUMN abstract_trimmed varchar(455) NOT NULL DEFAULT 'No text';
当使用addcolumn
添加列时,默认值为非易失性
指定时,将在语句和
结果存储在表的元数据中。该值将用于
所有现有行的列。如果未指定默认值,则为NULL
用过。在这两种情况下都不需要重写表
添加带有volatile默认值的列或更改
现有列将要求保存整个表及其索引
重写。作为例外,在更改现有文件的类型时
列,如果USING
子句未更改列内容和
旧类型是可强制为新类型的二进制类型或
新类型上的无约束域,不需要重写表;
但受影响列上的任何索引仍必须重建。桌子
和/或索引重建可能需要相当长的时间才能完成
大桌子;并且将暂时需要两倍的磁盘空间
使用“defaultValue”而不是“value”为新列设置默认值。要通过两个步骤完成此操作:
添加列,并将所有现有列上所需的值作为该列的默认值
然后从列中删除defaultValue:
这样做的一个优点是,如果您想在列中输入一个非静态值,它会计算一次并使用该值填充所有现有行(例如:时间戳),而不是可能为每一行更改重新计算它。感谢您提供的提示:varxhar(x)vs text with a constraint。我建议进行编辑以删除此项,因为它可能会分散对问题答案的注意力,但我将对此进行研究。干杯,@David:同意,text
/varchar
上的内容是一个旁白。我只想提一下,问题解决方案中提供的内容适用于MySQL,而不适用于MS SQL和,从这个问题很容易理解-Postgres.BTW为add column+not null
生成错误SQL的问题是:)@KrzysztofKaczor:是的,谢谢你指出。我在备选解决方案中添加了notnull
,以匹配“变通方法”(有或没有)。但否:具有默认值的列不会“接受NULL并使用默认值”。与任何其他值一样,显式NULL会覆盖默认值(如果列定义为非NULL
,则会触发异常)。只有在未向列写入任何内容(即,插入
(显式或隐式)中根本未提及该列,或者使用了默认
关键字时,才应用列默认值。不幸的是,这不仅指定了在运行数据库迁移时要向列中插入的值,但在以后添加行时,如果没有给定值,则插入哪个值。这可能不是你想要的。
ALTER TABLE layer
ADD COLUMN abstract_trimmed varchar(455) NOT NULL DEFAULT 'No text';
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")
}