2009-12-10 33 views
104

私は、次の表があります:私はparent_idに外部キー制約を追加するにはどうすればよい既存のSQLiteテーブルに外部キーを追加するにはどうすればよいですか?

CREATE TABLE child( 
    id INTEGER PRIMARY KEY, 
    parent_id INTEGER, 
    description TEXT); 

を?外部キーが有効であると仮定します。

ほとんどの例では、テーブルを作成していると仮定しています。既存の制約に制約を追加したいとします。

答えて

161

できません。

次のようにあなたのテーブルへの外部キーを追加するためのSQL-92の構文は次のようになりますが:

ALTER TABLE child ADD CONSTRAINT fk_child_parent 
        FOREIGN KEY (parent_id) 
        REFERENCES parent(id); 

SQLiteのはALTER TABLEコマンド(sqlite.org: SQL Features That SQLite Does Not Implement)のADD CONSTRAINTバリアントをサポートしていません。あなたは一時テーブルに既存のデータを保存する必要があります

残念ながら
CREATE TABLE child ( 
    id   INTEGER PRIMARY KEY, 
    parent_id INTEGER, 
    description TEXT, 
    FOREIGN KEY (parent_id) REFERENCES parent(id) 
); 

、古いテーブルを削除:次のように

したがって、sqliteの3.6.1に外部キーを追加する唯一の方法は、CREATE TABLE中にありますFK制約を使用して新しいテーブルを作成し、そのデータを一時テーブルからコピーし直します。 (sqlite.org - FAQ: Q11

+19

私は古いテーブルの名前を変更し、新しいテーブルを作成し、データをコピーする方が簡単だと思います。その後、古いテーブルを削除することができます。 – tuinstoel

+0

はい、それは簡単です。私はsqlite FAQを引用していました:http://www.sqlite.org/faq.html#q11。実際には、 'RENAME TO'は現在sqlite 3でサポートされているいくつかの' ALTER TABLE'亜種のうちの1つです。 –

+3

それはそうでなければなりません: FOREIGN KEY(parent_id)REFERENCES parent(id) 本当に、Jonathanは「親テーブル」の名前を付けます。 実際には、テーブルはpersonという名前にする必要がありますが、... – igorludi

43

テーブルを変更して制約を使用する列を追加すると、制約を追加できます。

まず、PARENT_IDせずにテーブルを作成します。

CREATE TABLE child( 
    id INTEGER PRIMARY KEY, 
    description TEXT); 

をその後、ALTER TABLE:

ALTER TABLE child ADD COLUMN parent_id INTEGER REFERENCES parent(id); 
+0

このシーケンスに慣れてもいいですが、これは実際の質問には答えません:*既存の制約に制約を追加したいです。* – Wolf

4

を使用している場合はFirefoxのアドオンあなたは次の操作を行うことができますsqliteのマネージャー:

テーブルを削除して再度作成する代わりに、このようにテーブルを修正することができます。

列のテキストボックスで、リストされた最後の列名を右クリックしてコンテキストメニューを表示し、列の編集を選択します。 TABLE定義の最後の列がPRIMARY KEYの場合は、最初に新しい列を追加し、新しい列の列の種類を編集してFOREIGN KEY定義を追加する必要があることに注意してください。列タイプボックス内 は、コンマとデータ型の後

FOREIGN KEY (parent_id) REFERENCES parent(id) 

定義を追加します。 [変更]ボタンをクリックし、[危険な操作]ダイアログボックスで[はい]ボタンをクリックします。

参考: Sqlite Manager

7

直接のSQLiteがサポートするコマンドを変更することhttps://www.sqlite.org/lang_altertable.html#otheralter

を確認してくださいスキーマだけは 「テーブルの名前を変更」し、上に示したコマンド「欄を追加」です。しかし、 アプリケーションでは、単純な操作シーケンスを使用してテーブル の形式に他の任意の変更を加えることができます。次のようにいくつかのテーブルXのスキーマ設計に任意 変更を行う手順は次のとおりです。

  1. 外部キー制約が有効になっている場合は、プラグマ FOREIGN_KEYS = OFFを使用してそれらを無効にします。
  2. トランザクションを開始します。
  3. テーブルXに関連付けられているすべてのインデックスとトリガーの形式を覚えておいてください。この情報は、下記の手順8で必要になります。 への1つの方法は、次のようなクエリを実行することです。SELECT type、sql FROM sqlite_master where tbl_name = 'X'。
  4. CREATE TABLEを使用して、 テーブルXの希望する改訂形式の新しいテーブル "new_X"を作成します。 "new_X"という名前が、既存のテーブル名と衝突しないようにしてください。
  5. のようなステートメント使用して新しいxにXから転送内容:新しいx SELECT INTO INSERT を... Xから
  6. ドロップ古いテーブルX:XにDROP TABLE Xの
  7. 変更新しいxの名前使用して: ALTER TABLE新しいx RENAMEは 変更を行う、
  8. 使用INDEXをCREATE X.、おそらくガイドとして上記のステップ3から保存 トリガとインデックスの古い形式を使用し、表Xに関連付けられたインデックスと トリガを再構築するためのトリガを作成します変更に応じていずれかのビューが スキーマ変更の影響を受けているように、テーブルXを参照している場合
  9. は、その後のDROP VIEWを使用してこれらのビューを削除し、変更が必要なものは何でもして 彼らはCREATE VIEWを使用してスキーマ の変化に対応するために再作成します。
  10. 外部キー制約が最初に有効になっている場合は、PRAGMA foreign_key_checkを実行して、スキーマの変更が外部キーの制約である を破損していないことを確認します。
  11. 手順2で開始したトランザクションをコミットします。
  12. 外部キー制約が最初に有効になっていた場合は、今すぐ を再び有効にします。

上記の手順は完全に一般的であり、 スキーマの変更によって表に格納された情報が変更されても機能します。列の順序を変更する、UNIQUE制約を追加または削除する またはPRIMARY KEY、CHECKまたはFOREIGN KEYまたはNOT NULL制約を追加する、 、列のデータ型を変更する、例えば。

-2

まず、以下のコードで子テーブルCidintとして、その後alter tableに列を追加します。

ALTER TABLE [child] 
    ADD CONSTRAINT [CId] 
    FOREIGN KEY ([CId]) 
    REFERENCES [Parent]([CId]) 
    ON DELETE CASCADE ON UPDATE NO ACTION; 
GO 
+1

これはSQLiteでは無効です。これはMS SQLの構文です。 – StilesCrisis

-1

あなた:あなたは、親テーブルの主キーとして外部キーCidを追加すると、子表の外部キーとして使用することができ、この方法は...それが私のために良いですと、それはあなたを助けることを願っていますできる!

次のコマンドを試してください。一時テーブルは必要ありません。それはAndroid Studioの私のために働く。

db.execSQL("alter table child add column newCol integer REFERENCES parent(parentId)"); 
+0

あなたは慎重に質問を読んでいないようです。問題は、制約を持つ列を追加するのではなく、外部制約のみを追加することでした。 – Wolf

0

はい、新しい列を追加しなくてもかまいません。あなたはこれをしようとする前に、完全にデータベースをバックアップする必要がありますので、データベースの破損を避けるためにそれを正しく行うには注意する必要があります:

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'; 

あなたは置き換える()アプローチを使用する場合は、最初に実行して置き換える()コマンドをテストするために、実行する前に、それが役に立つかもしれません:

select update(sql, ...) from SQLITE_MASTER where name = 'child' and type = 'table'; 
関連する問題