2009-12-10 106 views
104

我有以下表格:如何將外鍵添加到現有的SQLite表中?

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

如何添加上parent_id外鍵約束?假設外鍵已啓用。

大多數示例都假設您正在創建表格 - 我想將約束添加到現有表格中。

回答

161

你不能。

雖然SQL-92語法外鍵添加到您的表將如下所示:

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

SQLite不支持ADD CONSTRAINT變體ALTER TABLE命令(sqlite.org: SQL Features That SQLite Does Not Implement)的。

因此,在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

+19

我認爲重命名舊錶更容易,創建新表並將數據複製回來。然後,您可以刪除舊錶。 – tuinstoel 2009-12-11 19:20:24

+0

是的,那很容易。我只是引用了sqlite的常見問題:http://www.sqlite.org/faq.html#q11。實際上,'RENAME TO'是sqlite 3當前支持的少數幾個'ALTER TABLE'變體之一。 – 2009-12-11 19:37:51

+3

不應該是: FOREIGN KEY(parent_id)REFERENCES父級(id) 確實,Jonathan沒有給出「父表」的名稱。 其實表格應該是人名,但是... – igorludi 2012-09-07 08:51:29

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 2018-01-17 12:12:48

4

如果您使用的是Firefox插件sqlite的經理,你可以做到以下幾點:

而不是再次刪除和創建表,你可以像這樣修改它。

在列文本框中,右鍵單擊列出的最後一列名稱以調出上下文菜單並選擇編輯列。 請注意,如果TABLE定義中的最後一列是PRIMARY KEY,則需要首先添加一個新列,然後編輯新列的列類型以添加​​FOREIGN KEY定義。 內的列類型中,附加一個逗號和數據類型後

FOREIGN KEY (parent_id) REFERENCES parent(id) 

定義。 單擊更改按鈕,然後單擊危險操作對話框上的是按鈕。

參考: Sqlite Manager

7

請檢查https://www.sqlite.org/lang_altertable.html#otheralter

唯一模式變更命令直接SQLite的支持是 「重命名錶」和「添加列」上面顯示的命令。但是, 應用程序可以使用簡單的操作序列對錶 的格式進行其他任意更改。步驟進行是任意 更改某些表X的架構設計如下:

  1. 如果外鍵約束被啓用,使用PRAGMA foreign_keys = OFF禁用它們。
  2. 開始交易。
  3. 請記住所有索引和與 表X關聯的觸發器的格式。此信息將在下面的步驟8中需要。 這樣做的一個方法是運行如下查詢:SELECT type,sql FROM sqlite_master WHERE tbl_name ='X'。
  4. 使用CREATE TABLE構建一個新表格「new_X」,該表格位於 希望修改的表格格式X.當然,確保名稱「new_X」 不會與任何現有表名稱相沖突。使用的語句從X
  5. 內容傳送到一個new_x像:INSERT INTO SELECT的new_x ... FROM X.
  6. 刪除舊錶X:DROP TABLE X.
  7. 變化的new_x到X上使用的名稱: ALTER TABLE的new_x重命名爲X.
  8. 使用CREATE INDEX和CREATE TRIGGER來重建有十桌相關或許使用 觸發器和索引從上述步驟3爲指導保存的舊格式索引和 觸發器,使 變化視情況而定。
  9. 如果有任何意見請參考表X在由 架構變化的影響的方式,然後使用DROP VIEW丟棄這些意見,並重新 他們與任何變化都需要使用CREATE VIEW以適應架構 變化。
  10. 如果最初啓用了外鍵約束,則運行PRAGMA foreign_key_check以驗證模式更改沒有中斷 任何外鍵約束。
  11. 提交事務在步驟2中啓動。
  12. 如果最初啓用了外鍵約束,現在重新啓用它們 。

上述過程是完全一般的,並且即使 模式更改導致存儲在表中的信息發生變化,也會工作。因此, 上面的完整過程適用於刪除列, 更改列的順序,添加或刪除UNIQUE約束 或PRIMARY KEY,添加CHECK或FOREIGN KEY或NOT NULL約束, 或更改列的數據類型,例如。

-2

首先在子表Cidint然後alter table添加一列與下面的代碼。這樣你就可以添加外鍵Cid作爲父表的主鍵,把它作爲子表的外鍵...希望它會幫助你,因爲它是爲我好:

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 2017-10-27 00:27:47

-1

你能夠!

請嘗試以下命令,並且不需要臨時表。它適用於Android Studio中的我。

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

看來你沒有仔細閱讀過這個問題。問題是隻添加一個外部約束,而不是添加一個約束列。 – Wolf 2018-01-17 12:03:52

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'; 
相關問題