当前位置: 首页 > 面试题库 >

向现有表添加不可为空的列失败。是否会忽略“ alue”属性?

朱伯寅
2023-03-14
问题内容

背景:我们有一个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“添加列”文档。

但是,当应用迁移变更集时,出现以下异常

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


问题答案:

简短答案

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

解决方法

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

  1. 添加列

    ALTER TABLE layer ADD COLUMN abstract_trimmed varchar(455);
    
  2. 每行将其设置为非空值

    UPDATE table SET abstract_trimmed = 'No text';
    
  3. 添加NOT NULL约束

    ALTER TABLE layer ALTER COLUMN abstract_trimmed SET NOT NULL;
    

为什么?

列默认值仅通过插入到列中INSERT。“值”标签将为您完成此操作,但是 添加列 之后
。Liquibase尝试一步一步添加列,并设置NOT NULL约束:

ALTER TABLE layer ADD abstract_trimmed VARCHAR(455) NOT NULL;

…当表已经包含行时,这是 不可能 的。只是不够聪明。

替代解决方案

从PostgreSQL 8.0开始(到现在为止几乎永远如此),一种替代方法是添加 一个带有非nullDEFAULT的新列:

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

手册:

当添加了列ADD COLUMNDEFAULT指定了非易失性时,将在声明时评估默认值,并将结果存储在表的元数据中。该值将用于所有现有行的列。如果未DEFAULT指定,则使用NULL。在任何情况下都不需要重写该表。

添加具有volatile的列DEFAULT或更改现有列的类型将需要重写整个表及其索引。例外情况是,在更改现有列的类型时,如果该USING子句不更改列的内容,并且旧类型可以强制转换为新类型的二进制或新类型的不受约束的域,则无需重写表;否则,无需重写表。但是受影响的列上的所有索引仍必须重建。对于大型表,表和/或索引的重建可能会花费大量的时间。并且暂时需要多达两倍的磁盘空间。



 类似资料:
  • 我有一个工作的Java项目,它使用Access.accdb数据库存储数据。我正在为我的程序进行更新,为用户提供更多的功能。为了使其工作,我需要在现有的表中添加一个列,该列填充了数据。当我研究时,我发现UCanAccess不能支持 这是不幸的,但我明白,由于低级别的驱动程序不支持它,UCanAccess也不能支持它。 然后我找到了这个解决办法: 如何使用UCanAccess修改表 但这对我也不起作用

  • 问题内容: 我创建了一个固定大小的框架,现在我想在上面添加一些标签和其他小部件。但是我观察到,一旦我在该框架上添加新的小部件,其属性即不受尊重,即大小和默认的背景色设置不受尊重。 因此,在上面的示例中,如果我注释掉第4行和第6行,则可以看到具有蓝色背景色的固定大小的帧。我的要求是我想用这种颜色在此框架上添加其他一些小部件。 问题答案: 关于宽度和高度不被接受,但对于背景颜色,您是正确的。背景颜色不

  • 对于material-table,它们有一个属性来添加一个可编辑行,其中一个空的、可编辑的行被添加到表中,接受输入。我希望Ant的表组件具有相同的行为。您可以在底部的editable下拉切换下找到该行为的示例:https://material-table.com/#/docs/features/editable它们还有一个属性,用于将新行设置在顶部,这也是我想要的。 有没有人做过这个或者看到过这个

  • 问题内容: 我有一个由命令(使用任务)生成的文件。我不想将其添加到git存储库中,也不想添加到NPM项目中。 假设文件名是,我将其添加到文件中。 这足以避免将其上传到NPM注册表中吗? 我知道我可以添加肯定会忽略该文件的文件,但是如果已经这样做,则不会添加它。 问题答案: 如果项目同时具有和文件,则npm将 仅 使用该文件。 从文档中: 使用文件将东西从包装中取出。如果没有文件,但有 是 一个文件

  • 我正在寻找一种将任意长度的期货列表转换为期货列表的方法。我使用的是Playframework,所以最终,我真正想要的是一个<code>未来〔结果〕,但为了让事情更简单,让我们说<code>将来〔List[Int]]通常的方法是使用<code>Future.sequence(…) 例如,执行以下操作不起作用: 我希望能够将1和3从那里拉出来,而不是只得到异常。我尝试将来使用<code>。折叠,但这显

  • 问题内容: 我不知道如何使用Laravel框架向现有数据库表添加新列。 我试图使用…来编辑迁移文件。 在终端中,我执行和。 如何添加新列? 问题答案: 要创建迁移,您可以在Artisan CLI上使用migration:make命令。使用特定名称以避免与现有模型冲突 对于Laravel 3: 对于Laravel 5+: 然后,您需要使用该方法(在访问现有表而不是创建新表时)。您可以添加如下所示的列