次の表があります。
CREATE TABLE child(
id INTEGER PRIMARY KEY,
parent_id INTEGER,
description TEXT);
外部キー制約を追加するにはどうすればよいparent_id
ですか?外部キーが有効になっていると仮定します。
ほとんどの例では、テーブルを作成していると想定しています。既存の制約に制約を追加したいと思います。
次の表があります。
CREATE TABLE child(
id INTEGER PRIMARY KEY,
parent_id INTEGER,
description TEXT);
外部キー制約を追加するにはどうすればよいparent_id
ですか?外部キーが有効になっていると仮定します。
ほとんどの例では、テーブルを作成していると想定しています。既存の制約に制約を追加したいと思います。
回答:
できません。
テーブルに外部キーを追加するSQL-92構文は次のようになります。
ALTER TABLE child ADD CONSTRAINT fk_child_parent
FOREIGN KEY (parent_id)
REFERENCES parent(id);
SQLiteはADD CONSTRAINT
、ALTER TABLE
コマンドのバリアントをサポートしていません(sqlite.org:SQLiteが実装しないSQL機能)。
したがって、sqlite 3.6.1で外部キーを追加する唯一の方法はCREATE TABLE
次のとおりです。
CREATE TABLE child (
id INTEGER PRIMARY KEY,
parent_id INTEGER,
description TEXT,
FOREIGN KEY (parent_id) REFERENCES parent(id)
);
残念ながら、既存のデータを一時テーブルに保存し、古いテーブルを削除し、FK制約を使用して新しいテーブルを作成してから、一時テーブルからデータをコピーして戻す必要があります。(sqlite.org-FAQ:Q11)
RENAME TO
いくつかの一つでありALTER TABLE
、現在のsqlite 3でサポートされているバリアント
https://www.sqlite.org/lang_altertable.html#otheralterを確認してください
SQLiteが直接サポートする唯一のスキーマ変更コマンドは、上記の「テーブルの名前変更」と「列の追加」コマンドです。ただし、アプリケーションは、単純な一連の操作を使用して、テーブルの形式に他の任意の変更を加えることができます。一部のテーブルXのスキーマ設計に任意の変更を加える手順は次のとおりです。
- 外部キー制約が有効になっている場合は、PRAGMA foreign_keys = OFFを使用してそれらを無効にします。
- トランザクションを開始します。
- テーブルXに関連付けられているすべてのインデックスとトリガーの形式を覚えておいてください。この情報は、以下の手順8で必要になります。これを行う1つの方法は、次のようなクエリを実行することです:SELECTタイプ、sql FROM sqlite_master WHERE tbl_name = 'X'。
- CREATE TABLEを使用して、目的の改訂されたテーブルX形式の新しいテーブル「new_X」を作成します。「new_X」の名前が既存のテーブル名と衝突しないことを確認してください。
- INSERT INTO new_X SELECT ... FROM Xのようなステートメントを使用して、Xからnew_Xにコンテンツを転送します。
- 古いテーブルXをドロップします:DROP TABLEX。
- ALTER TABLE new_X RENAME TO Xを使用して、new_Xの名前をXに変更します。
- CREATE INDEXとCREATE TRIGGERを使用して、テーブルXに関連付けられているインデックスとトリガーを再構築します。おそらく、上記の手順3で保存したトリガーとインデックスの古い形式をガイドとして使用し、変更に応じて変更を加えます。
- スキーマの変更の影響を受ける方法でビューがテーブルXを参照している場合は、DROP VIEWを使用してそれらのビューを削除し、CREATE VIEWを使用したスキーマの変更に対応するために必要な変更を加えて再作成します。
- 外部キー制約が最初から有効になっている場合は、PRAGMA foreign_key_checkを実行して、スキーマの変更によって外部キー制約が壊れていないことを確認します。
- 手順2で開始したトランザクションをコミットします。
- 外部キー制約が元々有効になっていた場合は、ここで再度有効にします。
上記の手順は完全に一般的であり、スキーマの変更によってテーブルに格納されている情報が変更された場合でも機能します。したがって、上記の完全な手順は、列の削除、列の順序の変更、UNIQUE制約またはPRIMARY KEYの追加または削除、CHECKまたはFOREIGN KEYまたはNOT NULL制約の追加、または列のデータ型の変更などに適しています。
はい、できます。新しい列を追加する必要はありません。データベースの破損を防ぐために、正しく実行するように注意する必要があるため、これを試す前にデータベースを完全にバックアップする必要があります。
あなたの具体的な例について:
CREATE TABLE child(
id INTEGER PRIMARY KEY,
parent_id INTEGER,
description TEXT
);
--- create the table we want to reference
create table parent(id integer not null primary key);
--- now we add the foreign key
pragma writable_schema=1;
update SQLITE_MASTER set sql = replace(sql, 'description TEXT)',
'description TEXT, foreign key (parent_id) references parent(id))'
) where name = 'child' and type = 'table';
--- test the foreign key
pragma foreign_keys=on;
insert into parent values(1);
insert into child values(1, 1, 'hi'); --- works
insert into child values(2, 2, 'bye'); --- fails, foreign key violation
より一般的には:
pragma writable_schema=1;
// replace the entire table's SQL definition, where new_sql_definition contains the foreign key clause you want to add
UPDATE SQLITE_MASTER SET SQL = new_sql_definition where name = 'child' and type = 'table';
// alternatively, you might find it easier to use replace, if you can match the exact end of the sql definition
// for example, if the last column was my_last_column integer not null:
UPDATE SQLITE_MASTER SET SQL = replace(sql, 'my_last_column integer not null', 'my_last_column integer not null, foreign key (col1, col2) references other_table(col1, col2)') where name = 'child' and type = 'table';
pragma writable_schema=0;
いずれの場合も、変更を行う前に、まずSQL定義を確認する必要があります。
select sql from SQLITE_MASTER where name = 'child' and type = 'table';
replace()アプローチを使用する場合は、実行する前に、次のコマンドを実行してreplace()コマンドをテストすると便利です。
select replace(sql, ...) from SQLITE_MASTER where name = 'child' and type = 'table';
Firefoxアドオンsqlite-managerを使用している場合は、次の操作を実行できます。
テーブルを削除して再度作成する代わりに、次のように変更することができます。
[列]テキストボックスで、リストされている最後の列名を右クリックしてコンテキストメニューを表示し、[列の編集]を選択します。TABLE定義の最後の列がPRIMARY KEYである場合、最初に新しい列を追加してから、新しい列の列タイプを編集してFOREIGN KEY定義を追加する必要があることに注意してください。[列タイプ]ボックス内に、カンマと
FOREIGN KEY (parent_id) REFERENCES parent(id)
データ型の後の定義。[変更]ボタンをクリックし、[危険な操作]ダイアログボックスの[はい]ボタンをクリックします。
リファレンス: Sqlite Manager
基本的にはできませんが、状況を回避できます。
外部キー制約を既存のテーブルに追加する正しい方法は、次のコマンドです。
db.execSQL("alter table child add column newCol integer REFERENCES parent(parent_Id)");
そして、コピーPARENT_IDのにデータをNEWCOLしてから削除PARENT_IDの列が。したがって、一時テーブルは必要ありません。
最初の子テーブルの列を追加しCid
てint
、その後alter table
、以下のコードで。このようにして、外部キーCid
を親テーブルの主キーとして追加し、それを子テーブルの外部キーとして使用することができます。
ALTER TABLE [child]
ADD CONSTRAINT [CId]
FOREIGN KEY ([CId])
REFERENCES [Parent]([CId])
ON DELETE CASCADE ON UPDATE NO ACTION;
GO