SQL
Kaskadowe usuwanie
Szukaj…
PRZY USUNIĘCIU KASKADA
Załóżmy, że masz aplikację zarządzającą pokojami.
Załóżmy ponadto, że twoja aplikacja działa na zasadzie według klienta (dzierżawcy).
Masz kilku klientów.
Twoja baza danych będzie więc zawierać jedną tabelę dla klientów i jedną dla pokoi.
Teraz każdy klient ma N pokoi.
Powinno to oznaczać, że masz klucz obcy na stole w pokoju, odnoszący się do stołu klienta.
ALTER TABLE dbo.T_Room WITH CHECK ADD CONSTRAINT FK_T_Room_T_Client FOREIGN KEY(RM_CLI_ID)
REFERENCES dbo.T_Client (CLI_ID)
GO
Zakładając, że klient przejdzie na inne oprogramowanie, będziesz musiał usunąć jego dane z twojego oprogramowania. Ale jeśli tak
DELETE FROM T_Client WHERE CLI_ID = x
Wtedy otrzymasz naruszenie klucza obcego, ponieważ nie możesz usunąć klienta, gdy nadal ma pokoje.
Teraz będziesz musiał napisać kod w swojej aplikacji, który usuwa pokoje klienta przed usunięciem klienta. Załóżmy ponadto, że w przyszłości do bazy danych zostanie dodanych wiele innych zależności kluczy obcych, ponieważ funkcjonalność aplikacji się rozszerza. Okropny. Dla każdej modyfikacji w bazie danych będziesz musiał dostosować kod aplikacji w N miejscach. Być może będziesz musiał dostosować kod również w innych aplikacjach (np. Interfejsy do innych systemów).
Istnieje lepsze rozwiązanie niż robienie tego w kodzie.
Możesz po prostu dodać ON DELETE CASCADE
do swojego klucza obcego.
ALTER TABLE dbo.T_Room -- WITH CHECK -- SQL-Server can specify WITH CHECK/WITH NOCHECK
ADD CONSTRAINT FK_T_Room_T_Client FOREIGN KEY(RM_CLI_ID)
REFERENCES dbo.T_Client (CLI_ID)
ON DELETE CASCADE
Teraz możesz powiedzieć
DELETE FROM T_Client WHERE CLI_ID = x
a pokoje są automatycznie usuwane po usunięciu klienta.
Problem rozwiązany - bez zmian kodu aplikacji.
Jedno słowo ostrzeżenia: w Microsoft SQL-Server to nie zadziała, jeśli masz tabelę, która odwołuje się do siebie. Więc jeśli spróbujesz zdefiniować kaskadę usuwania w rekurencyjnej strukturze drzewa, to tak:
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_T_FMS_Navigation_T_FMS_Navigation]') AND parent_object_id = OBJECT_ID(N'[dbo].[T_FMS_Navigation]'))
ALTER TABLE [dbo].[T_FMS_Navigation] WITH CHECK ADD CONSTRAINT [FK_T_FMS_Navigation_T_FMS_Navigation] FOREIGN KEY([NA_NA_UID])
REFERENCES [dbo].[T_FMS_Navigation] ([NA_UID])
ON DELETE CASCADE
GO
IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_T_FMS_Navigation_T_FMS_Navigation]') AND parent_object_id = OBJECT_ID(N'[dbo].[T_FMS_Navigation]'))
ALTER TABLE [dbo].[T_FMS_Navigation] CHECK CONSTRAINT [FK_T_FMS_Navigation_T_FMS_Navigation]
GO
to nie zadziała, ponieważ serwer Microsoft-SQL nie pozwala na ustawienie klucza obcego przy ON DELETE CASCADE
na rekurencyjnej strukturze drzewa. Jednym z powodów jest to, że drzewo jest prawdopodobnie cykliczne, co może doprowadzić do impasu.
Z drugiej strony PostgreSQL może to zrobić;
wymaga się, aby drzewo nie było cykliczne.
Jeśli drzewo jest cykliczne, pojawi się błąd czasu wykonywania.
W takim przypadku wystarczy samodzielnie zaimplementować funkcję usuwania.
Słowo ostrzeżenia:
Oznacza to, że nie możesz już po prostu usuwać i ponownie wstawiać tabeli klienta, ponieważ jeśli to zrobisz, spowoduje to usunięcie wszystkich wpisów w „T_Room” ... (brak aktualizacji innych niż delta)