【问题标题】:Liquibase SQL error -- adds column which is not null to table with existing dataLiquibase SQL 错误 - 将不为空的列添加到包含现有数据的表中
【发布时间】:2015-12-19 18:08:00
【问题描述】:

我正在尝试使用 Liquibase 将一个数据库转换为另一个数据库。我有两个数据库,想在其中一个上运行 SQL 脚本,使其与另一个相同。我正在使用 Liquibase 3.4.1 版和两个 H2 数据库。为了生成 SQL 脚本,我首先使用 diffChangeLog 命令生成 diff xml,该命令运行良好。 (实际上有一个问题:它会生成类型为 VARCHAR 且 autoIncrement 设置为 true 的列,但可以手动删除)。然后我使用命令 updateSQL 从 diff xml 生成 SQL 文件。 SQL 文件包含以下行:

ALTER TABLE PUBLIC.USERS ADD ENABLED BOOLEAN(1) NOT NULL; 

最初,db 包含一个名为 USERS 的表,其中包含两列:USER 和 PASSWORD,其中包含一行数据(user1,password)。 SQL 脚本此时失败,因为它试图创建一个新列,其第一行的条目将设置为 NULL,但该列应该为 NOT NULL。错误是:

错误:“ENABLED”列不允许为 NULL;

SQL 语句: ALTER TABLE PUBLIC.USERS ADD ENABLED BOOLEAN(1) NOT NULL [23502-187]

SQL 状态:23502

错误代码:23502

错误发生在:ALTER TABLE PUBLIC.USERS ADD ENABLED BOOLEAN(1) NOT NULL

我可以尝试手动删除 NOT NULL 条件,但这并不适用于所有情况,如下所述。当我删除 NOT NULL 时,会发生这种情况:

执行以下行时发生另一个相关错误(就在上面的行之后):

ALTER TABLE PUBLIC.USERS ADD USERNAME VARCHAR(50) NOT NULL;  

请注意,它正在尝试添加列“USERNAME”,而不是原始数据库已有的“USER”。

它给出了同样的错误,当我删除 NOT NULL 时,又出现了另一个错误:

错误:列“USERNAME”不能为空;

SQL语句:ALTER TABLE PUBLIC.USERS ADD CONSTRAINT CONSTRAINT_4 PRIMARY KEY (USERNAME)[90023-187]

SQL 状态:90023

错误代码:90023

错误发生在:ALTER TABLE PUBLIC.USERS ADD CONSTRAINT CONSTRAINT_4 PRIMARY KEY (USERNAME)

由于列是主键,它不能为空。

有没有办法轻松解决这个问题? Liquibase 中是否有一个选项可以消除这些错误?

【问题讨论】:

    标签: h2 liquibase


    【解决方案1】:

    首先添加列,没有 NOT NULL 设置。然后更新现有行的列。最后,应用 NOT NULL 约束。

    <addNotNullConstraint catalogName="cat"
                columnDataType="int"
                columnName="id"
                defaultNullValue="A String"
                schemaName="public"
                tableName="person"/>
    

    我不建议使用 defaultValue 设置,因为如果您的行数很高,它可能会锁定表。对生产中的维护窗口非常不利。

    【讨论】:

    • 这是一个不错的选择。我之前没有遇到过&lt;addNotNullConstraint&gt; 元素。 (不过,我不禁要注意您的...有趣的示例值,其中您正在为 int 列指定默认字符串值。:-))
    【解决方案2】:

    当您添加NOT NULL 列时,诀窍是给它一个默认值。在您的 Liquibase XML 中,对于列定义,您需要这样的内容:

    <column
        name="ENABLED"
        type="BOOLEAN(1)"
        defaultValue="0"
    >
    

    这应该生成一个适合平台的NOT NULL WITH DEFAULT 0 子句。

    【讨论】:

    • 但这在功能上有所不同,因为它会在升级后继续接受空值,填写默认值。
    【解决方案3】:

    这取决于您的数据库。 Mysql/Mariadb 可以这样简单:

    <changeSet author="tibi" id="201803062100-1">
        <addColumn tableName="jhi_user">
            <column name="status" type="varchar(20)" value="ENABLED" />
            <constraints nullable="false" />
        </addColumn>
    </changeSet>
    

    H2 不允许这样做,所以你需要这个:

    <changeSet author="tibi" id="201803062100-1">
        <addColumn tableName="jhi_user">
            <column name="status" type="varchar(20)" value="ENABLED" />
    
        </addColumn>
        <addNotNullConstraint columnDataType="varchar(20)" columnName="status" tableName="jhi_user" />
    </changeSet>
    

    或根据您的情况:

    <changeSet author="tibi" id="201803062100-1">
        <addColumn tableName="jhi_user">
            <column name="status" type="boolean" value="0" />
    
        </addColumn>
        <addNotNullConstraint columnDataType="boolean" columnName="status" tableName="jhi_user" />
    </changeSet>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-27
      • 1970-01-01
      • 2016-05-11
      • 2021-10-05
      • 2012-11-26
      • 2015-02-03
      相关资源
      最近更新 更多