背景
PlayFrameworkで構築したWebアプリケーションのデータベースマイグレーションツールとしてevolution
を使用しています。
データベースはMySQL
初期に構築(して未使用だった)テーブルの定義が誤っていました。
具体的には不要なユニークキーを付与してしまっていました。(重複が発生してレコード追加できない不具合発生)
削除したいがテーブル定義を記述したスクリプトを修正するとデータが失われてしまうので追加スクリプトにDROPを記載して対応したい。
問題点
キーの削除は、UP節にalter table xxx drop key xxx
で可能です。を記載すればOKです。
問題はDOWN節でCREATEできないこと(キー重複エラーになる)。
このため、UP節が2回実行されると存在しないキーを削除しようとするのでマイグレーション操作がエラーになってしまいます。
IF EXISTS
はテーブルの削除(DROP TABLE
)はサポートしていますがALTER TABLE
ではサポートされていません。
MySQL :: MySQL 5.6 リファレンスマニュアル :: 13.1.7 ALTER TABLE 構文
対応策
information_schema
で存在をチェックして動的にSQL文を作成することで複数回実行してもパスするようになりました。
インデックス、ユニークキーの場合
set @tablename='テーブル名';
set @indexname='インデックス名';
set @var=if((SELECT true FROM information_schema.STATISTICS WHERE
INDEX_SCHEMA = DATABASE() AND
TABLE_NAME = @tablename AND
INDEX_NAME = indexname) = true,concat('ALTER TABLE ', @tablename, ' drop key ', @indexname),'select 1');
prepare stmt from @var;
execute stmt;
deallocate prepare stmt;
外部キーの場合
# --- !Ups
set @tablename='テーブル名';
set @constraintname='外部キー名';
set @var=if((SELECT true FROM information_schema.table_constraints WHERE
table_SCHEMA = database()
and table_name = @tablename
and constraint_type="FOREIGN KEY"
and CONSTRAINT_NAME = @constraintname) = true,concat('ALTER TABLE ', @tablename, ' drop FOREIGN KEY ', @constraintname),'select 1');
prepare stmt from @var;
execute stmt;
deallocate prepare stmt;
参考
以下のQ&Aの上位回答のあわせ技です。
mysql - Drop foreign key only if it exists - Stack Overflow
https://stackoverflow.com/questions/17161496/drop-foreign-key-only-if-it-exists