在 Liquibase 中,如何将新的 column/field 添加到现有的复合主键

In Liquibase, how to add a new column/field to an existing composite primary key

我们有一个 现有 table,其中有 2 个现有列用作复合主键。它们的设置与此非常相似:

<!--  WE CAN NO LONGER MODIFY THIS CHANGESET  -->

<changeSet author="an_awesome_author" id="EXAMPLE-01">
  <createTable tableName="our_awesome_table">
    <column name="source" type="varchar(32)">
      <constraints 
          primaryKey="true" 
          nullable="false" 
          primaryKeyName="CPK_OUR_AWESOME_TABLE"/>
    </column>
    <column
        name="external_id"
        type="varchar(255)">
      <constraints 
          primaryKey="true" 
          nullable="false"  
          primaryKeyName="CPK_OUR_AWESOME_TABLE"/>
    </column>
  </createTable>
</changeSet>

随后我们注意到可以有多个记录具有相同的 source & external_id ()。提交数据的小组定期提交,他们向我们保证他们绝不会在同一批数据中使用 sourceexternal_id 的相同组合。

因此(出于超出此问题的原因)我们决定添加一个 created_at 字段,该字段不可为空,默认为每条记录添加到 table.这并不难,例如我们可以 运行 这对 changeSets

<!-- WE ARE TRYING TO FINALIZE THESE CHANGESETS -->

<changeSet author="yours_truly"
           id="EXAMPLE-02-01">
  <addColumn tableName="our_awesome_table">
    <column name="CREATED_AT"
            type="datetime"
            valueDate="current_datetime"
            defaultValueDate="current_datetime" />
    <!-- the above:
      adds the new field
      sets the type
      adds the current timestamp to existing records
      will default to the current timestamp for new records
    -->
  </addColumn>
</changeSet>
<changeSet author="yours_truly"
           id="EXAMPLE-02-02">
  <addNotNullConstraint tableName="our_awesome_table"
                        columnName="CREATED_AT"/>
  <!-- the above:
    now that every record has a value in the newly created field,
    we can add a constrant preventing null entries into the column
  -->
</changeSet>

但是,我们还需要添加 created_at 到我们现有的复合主键!

如果我在创建字段时尝试将主键作为约束包括在内,它会抱怨 table 只能有一个主键 —尽管事实上它已经是一个复合键,我只是想将它添加到已经存在的复合键中。 但它也抱怨 created_at 时间戳为空。所以,我不确定哪个是真正的问题‍♂️,但它在这里肯定行不通。

例如

<changeSet author="yours_truly"
           id="EXAMPLE-02-01">
  <addColumn tableName="our_awesome_table">
    <column name="CREATED_AT"
            type="datetime"
            valueDate="current_datetime"
            defaultValueDate="current_datetime">
      <constraints primaryKey="true"
                   primaryKeyName="PK_OUR_AWESOME_TABLE"/>
      <!-- this constraints causes multiple problems -->
    </column>
  </addColumn>
</changeSet>

结果类似于:

[ERROR]      Reason: liquibase.exception.DatabaseException: ORA-02260: table can have only one primary key
[ERROR]  [Failed SQL: ALTER TABLE OUR_AWESOME_TABLE.OUR_AWESOME_TABLE ADD CREATED_AT TIMESTAMP DEFAULT SYSTIMESTAMP PRIMARY KEY NOT NULL]

如果我尝试将主键作为 <constraint> 包含在我们添加不可为空约束的 changeSet 中,那么我基本上被告知我不能在那里使用 <constraints> 并且相反需要 <addXxxConstraint> 列表之一,列表中有一个 <addPrimaryKey> — 这听起来像是正确的约束。

因此,如果我将第二个 changeSet 更改为这样的内容,我希望它能正常工作:

<changeSet author="yours_truly"
           id="EXAMPLE-02-02">
  <addNotNullConstraint tableName="our_awesome_table"
                        columnName="CREATED_AT"/>
  <addPrimaryKey tableName="our_awesome_table"
                 columnNames="CREATED_AT"
                 primaryKeyName="CPK_OUR_AWESOME_TABLE"/>
</changeSet>

但是 — 正如您可能猜到的那样 — 它不起作用。相反,它告诉我,cvc-complex-type.3.2.2: Attribute 'primaryKeyName' is not allowed to appear in element 'addPrimaryKey'.


那么,如何向现有的复合主键添加一个新的不可空字段?

addPrimaryKey-Type 没有 primaryKeyName 属性 - 可以通过 constraintName.

设置约束的名称

但这行不通,因为您不能在 oracle 中更改主键。相反,您必须 drop the primary key (很可能是相应的索引),然后重新创建它,包括 columnNames:

中您想要的列
<changeSet author="yours_truly"
           id="EXAMPLE-02-02">
  <addNotNullConstraint tableName="our_awesome_table"
                        columnName="CREATED_AT"/>

  <dropPrimaryKey tableName="our_awesome_table"
                 dropIndex="true"
                 constraintName="CPK_OUR_AWESOME_TABLE"/>

  <addPrimaryKey tableName="our_awesome_table"
                 columnNames="external_id, created_at"
                 constraintName="CPK_OUR_AWESOME_TABLE"/>
</changeSet>