18

背景: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")
            }
        }
    }

これにより、既存のすべての行に「テキストなし」という値が挿入され、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、Postgres9.0を使用しています

4

3 に答える 3

24

短い答え

列の作成時にnull以外の制約を追加する場合、「value」属性は機能しません(これはドキュメントに記載されていません)。生成されたSQLは実行できなくなります。

回避策

質問で説明されている回避策は、進むべき道です。結果のSQLは次のようになります。

  1. 列を追加します

    ALTER TABLE layer ADD COLUMN abstract_trimmed varchar(455);
    
  2. すべての行でnull以外の値に設定します

    UPDATE table SET abstract_trimmed = 'No text';
    
  3. NOTNULL制約を追加します

    ALTER TABLE layer ALTER COLUMN abstract_trimmed SET NOT NULL;
    

なんで?

列のデフォルトは、。が付いている列にのみ挿入されますINSERT。「value」タグがそれを行いますが、列が追加された後です。Liquibaseは、NOT NULL制約を設定して、1つのステップで列を追加しようとします。

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

...これは、テーブルにすでに行が含まれている場合は不可能です。それは十分に賢くないだけです。

代替ソリューション

PostgreSQL 8.0以降(今ではほぼ永久に)、代替手段はnull以外DEFAULTの新しい列を追加することです。

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

マニュアル:

列が追加され、ADD COLUMN不揮発性DEFAULTが指定されている場合、デフォルトはステートメントの時点で評価され、結果はテーブルのメタデータに格納されます。その値は、既存のすべての行の列に使用されます。noDEFAULTが指定されている場合、NULLが使用されます。どちらの場合も、テーブルの書き換えは必要ありません。

揮発性の列を追加しDEFAULTたり、既存の列のタイプを変更したりすると、テーブル全体とそのインデックスを書き換える必要があります。例外として、既存の列のタイプを変更するときに、USING句が列の内容を変更せず、古いタイプが新しいタイプに対してバイナリ強制可能であるか、新しいタイプに対する制約のないドメインである場合、テーブルの書き換えは必要ありません。ただし、影響を受ける列のインデックスはすべて再構築する必要があります。テーブルやインデックスの再構築は、大きなテーブルの場合、かなりの時間がかかる場合があります。一時的に2倍のディスク容量が必要になります。

于 2012-01-18T07:21:05.537 に答える
2

「value」の代わりに「defaultValue」を使用して、新しい列のデフォルト値を設定します。

于 2013-12-19T14:08:09.297 に答える