web-dev-qa-db-ja.com

既存のSQLiteテーブルに制約を追加します

私はSQLiteを使用しています。これは サポートしていません 既存のテーブルに 制約 を追加します。

だから私はこのようなことをすることはできません(例として):

ALTER TABLE [Customer]
ADD CONSTRAINT specify_either_phone_or_email
CHECK (([Phone] IS NOT NULL) OR ([Email] IS NOT NULL));

このシナリオの回避策はありますか?

知っている:

  • 新しいテーブルに制約を追加できますが、それは新しいものではありません(そして、それは私のORM、EF Coreによって生成されます)
  • 「テーブルの再構築」(テーブルの名前の変更、新しいテーブルの作成、古いデータのコピー、一時テーブルの削除)を実行できますが、それは非常に複雑に思えます

アイデア

  • スキーマを変更して、テーブルのコピーを新しいテーブルに作成できますか?
  • または、何らかの方法でスキーマを「取得」し、SQLスクリプトで編集してから、そのスキーマを含むテーブルを追加しますか?
13
grokky

スキーマを変更してテーブルのコピーを作成するには、作成とコピーを手動で行う必要があります。

BEGIN;
CREATE TABLE Customer_new (
    [...],
    CHECK ([...])
);
INSERT INTO Customer_new SELECT * FROM Customer;
DROP TABLE Customer;
ALTER TABLE Customer_new RENAME TO Customer;
COMMIT;

スキーマを読み取るには、 .schema Customerコマンドラインシェルsqlite3を実行します。これにより、編集および実行できるCREATETABLEステートメントが得られます。


テーブルを所定の位置に変更するには、バックドアを使用できます。

まず、実際のテーブル定義を読み取ります(これは、.schemaから取得するものと同じです)。

SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'Customer';

その文字列にCHECK制約を追加し、 PRAGMA writable_schema = 1; を使用してsqlite_masterへの書き込みアクセスを有効にし、新しいテーブル定義をその文字列に書き込みます。

UPDATE sqlite_master SET sql='...' WHERE type='table' AND name='Customer';

次に、データベースを再度開きます。

[〜#〜]警告[〜#〜]:これは、テーブルのディスク上のフォーマットを変更しない変更に対してのみ機能します。レコード形式を変更する変更(フィールドの追加/削除、ROWIDの変更、内部インデックスを必要とする制約の追加など)を行うと、データベースがひどく爆発します。

10
CL.