SQLite obsługuje bardzo ograniczony podzbiór ALTER TABLE
oświadczenie. Jedyne rzeczy, które możesz zrobić z ALTER TABLE
w SQLite to zmiana nazwy tabeli, zmiana nazwy kolumny w tabeli lub dodanie nowej kolumny do istniejącej tabeli.
Innymi słowy, nie możesz użyć ALTER TABLE
aby dodać klucz obcy do istniejącej tabeli, tak jak w innych systemach zarządzania bazami danych.
Dlatego jedynym sposobem na „dodanie” klucza obcego do istniejącej tabeli w SQLite jest utworzenie nowej tabeli z kluczem obcym, a następnie przeniesienie danych do nowej tabeli.
Można to zrobić na więcej niż jeden sposób, ale jest sposób zalecany.
Zalecany sposób
Dokumentacja SQLite zaleca 12-etapowy proces wprowadzania zmian w schemacie do tabeli.
Na potrzeby tego artykułu zajmiemy się tylko dodawaniem klucza obcego.
Aby było to trochę realistyczne, upewnimy się, że tabela zawiera już dane.
Oryginalna tabela bez klucza obcego
Najpierw utwórzmy stół bez klucz obcy i wypełnij go danymi.
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 );
Właściwie tutaj stworzyłem dwie tabele i wypełniłem je danymi. Dwie tabele, bo jedna (Typy ) będzie miał klucz podstawowy, a drugi (Zwierzęta ) będzie miał klucz obcy.
Zauważ, że nie utworzyłem klucza obcego.
Możemy sprawdzić, czy nie ma kluczy obcych, uruchamiając następujące polecenie:
PRAGMA foreign_key_list(Pets);
W moim przypadku otrzymuję następujący wynik:
(To pole jest puste, ponieważ w tej tabeli nie ma ograniczeń klucza obcego).
Teraz „dodajmy” klucz obcy.
Dodaj klucz obcy
Poniższy kod dodaje klucz obcy do naszej tabeli, tworząc nową tabelę z ograniczeniem klucza obcego, przesyłając dane do tej tabeli, upuszczając oryginalną tabelę, a następnie zmieniając nazwę nowej tabeli na nazwę oryginalnej tabeli.
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;
Gotowe.
Jeśli potrzebujesz zrekonstruować jakiekolwiek indeksy, wyzwalacze lub widoki, zrób to po ALTER TABLE
instrukcja zmieniająca nazwę tabeli (tuż przed COMMIT
).
Teraz ponownie sprawdźmy tabelę pod kątem ograniczeń kluczy obcych.
.mode line
PRAGMA foreign_key_list(Pets);
Wynik (przy użyciu wyjścia pionowego):
id = 0 seq = 0 table = Types from = TypeId to = TypeId on_update = NO ACTION on_delete = NO ACTION match = NONE
Tym razem możemy zobaczyć szczegóły ograniczenia klucza obcego.
Zauważ, że pierwsza linia mojego polecenia (.mode line
) nie ma nic wspólnego z tworzeniem klucza obcego. Umieściłem go tam wyłącznie po to, aby zmienić sposób, w jaki mój terminal wyświetla wynik (abyś nie musiał przewijać na boki, aby wyświetlić wynik).
Alternatywna metoda
Patrząc na poprzedni przykład, możesz pomyśleć, że jest na to bardziej efektywny sposób. Na przykład możesz to zrobić tak:
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;
I to prawda. W moim przykładzie ta metoda działa równie dobrze.
Ale ta metoda może również uszkodzić odniesienia do tabeli w dowolnych istniejących wyzwalaczach, widokach i ograniczeniach kluczy obcych.
Jeśli więc Twoja tabela ma już istniejące wyzwalacze, widoki lub ograniczenia klucza obcego, prawdopodobnie bezpieczniej jest użyć zalecanej metody.