SQLite поддържа много ограничено подмножество от ALTER TABLE
изявление. Единствените неща, които можете да правите с ALTER TABLE
в SQLite е преименуване на таблица, преименуване на колона в таблица или добавяне на нова колона към съществуваща таблица.
С други думи, не можете да използвате ALTER TABLE
за да добавите външен ключ към съществуваща таблица, както можете в други системи за управление на бази данни.
Следователно единственият начин да „добавите“ външен ключ към съществуваща таблица в SQLite е да създадете нова таблица с външен ключ, след което да прехвърлите данните в новата таблица.
Има повече от един начин да направите това, но има препоръчан начин.
Препоръчителният начин
Документацията на SQLite препоръчва процес от 12 стъпки за промяна на схемата в таблица.
За целите на тази статия ще се заемем само с добавянето на външен ключ.
За да го направим донякъде реалистично, ще се уверим, че таблицата вече съдържа данни.
Оригинална таблица без външен ключ
Първо, нека създадем таблица без външен ключ и го попълнете с данни.
CREATE TABLE Types(
TypeId INTEGER PRIMARY KEY,
Type
);
CREATE TABLE Pets(
PetId INTEGER PRIMARY KEY,
PetName,
TypeId
);
INSERT INTO Types VALUES
( NULL, 'Dog' ),
( NULL, 'Cat' ),
( NULL, 'Parakeet' ),
( NULL, 'Hamster' );
INSERT INTO Pets VALUES
( NULL, 'Brush', 3 ),
( NULL, 'Tweet', 3 ),
( NULL, 'Yelp', 1 ),
( NULL, 'Woofer', 1 ),
( NULL, 'Fluff', 2 );
Всъщност тук създадох две таблици и ги попълних с данни. Две таблици, защото една (Типове ) ще има първичния ключ, а другият (Домашни любимци ) ще има външния ключ.
Забележете, че не съм създал външен ключ.
Можем да проверим дали няма външни ключове, като изпълним следната команда:
PRAGMA foreign_key_list(Pets);
В моя случай получавам следния резултат:
(Това е празно, защото в тази таблица няма ограничения за външни ключове.)
Сега нека „добавим“ външен ключ.
Добавяне на външен ключ
Следващият код добавя външен ключ към нашата таблица, като създава нова таблица с ограничение за външен ключ, прехвърля данните в тази таблица, премахва оригиналната таблица, след което преименува новата таблица на името на оригиналната таблица.
PRAGMA foreign_keys = OFF;
BEGIN TRANSACTION;
CREATE TABLE Pets_new(
PetId INTEGER PRIMARY KEY,
PetName,
TypeId,
FOREIGN KEY(TypeId) REFERENCES Types(TypeId)
);
INSERT INTO Pets_new SELECT * FROM Pets;
DROP TABLE Pets;
ALTER TABLE Pets_new RENAME TO Pets;
COMMIT;
PRAGMA foreign_keys = ON;
Готово.
Ако трябва да реконструирате някакви индекси, тригери или изгледи, направете това след ALTER TABLE
оператор, който преименува таблицата (точно преди COMMIT
).
Сега нека отново проверим таблицата за ограничения на външния ключ.
.mode line
PRAGMA foreign_key_list(Pets);
Резултат (с помощта на вертикален изход):
id = 0 seq = 0 table = Types from = TypeId to = TypeId on_update = NO ACTION on_delete = NO ACTION match = NONE
Този път можем да видим подробностите за ограничението на външния ключ.
Обърнете внимание, че първият ред на моята команда (.mode line
) няма нищо общо със създаването на външен ключ. Поставих го там единствено, за да променя начина, по който терминалът ми извежда резултата (така че да не се налага да превъртате настрани, за да видите резултата).
Алтернативен метод
Когато разглеждате предишния пример, може да си помислите, че има по-ефективен начин да го направите. Например можете да го направите така:
PRAGMA foreign_keys = OFF;
BEGIN TRANSACTION;
ALTER TABLE Pets RENAME TO Pets_old;
CREATE TABLE Pets(
PetId INTEGER PRIMARY KEY,
PetName,
TypeId,
FOREIGN KEY(TypeId) REFERENCES Types(TypeId)
);
INSERT INTO Pets SELECT * FROM Pets_old;
DROP TABLE Pets_old;
COMMIT;
PRAGMA foreign_keys = ON;
И е вярно. С моя пример този метод работи също толкова добре.
Но този метод също има потенциал да повреди препратките към таблицата във всички съществуващи задействания, изгледи и ограничения на външния ключ.
Така че, ако вашата таблица вече има съществуващи задействания, изгледи или ограничения за външен ключ, вероятно е по-безопасно да използвате препоръчания метод.