SQL
Trapsgewijze verwijdering
Zoeken…
BIJ VERWIJDER CASCADE
Stel dat u een applicatie hebt die kamers beheert.
Ga er verder vanuit dat uw applicatie per klant werkt (huurder).
Je hebt verschillende klanten.
Uw database bevat dus één tabel voor clients en één voor kamers.
Nu heeft elke klant N kamers.
Dit zou moeten betekenen dat u een externe sleutel op uw kamertafel hebt, verwijzend naar de clienttafel.
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
Ervan uitgaande dat een client naar andere software gaat, moet u zijn gegevens in uw software verwijderen. Maar als je dat doet
DELETE FROM T_Client WHERE CLI_ID = x
Dan krijg je een overtreding van een externe sleutel, omdat je de client niet kunt verwijderen wanneer hij nog kamers heeft.
Nu zou u code in uw toepassing hebben geschreven die de kamers van de client verwijdert voordat de client wordt verwijderd. Veronderstel verder dat in de toekomst veel meer externe sleutelafhankelijkheden zullen worden toegevoegd aan uw database, omdat de functionaliteit van uw toepassing wordt uitgebreid. Verschrikkelijk. Voor elke wijziging in uw database moet u de code van uw toepassing op N plaatsen aanpassen. Mogelijk moet u de code ook in andere toepassingen aanpassen (bijvoorbeeld interfaces met andere systemen).
Er is een betere oplossing dan het in uw code te doen.
U kunt gewoon ON DELETE CASCADE
aan uw externe sleutel.
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
Nu kun je zeggen
DELETE FROM T_Client WHERE CLI_ID = x
en de kamers worden automatisch verwijderd wanneer de client wordt verwijderd.
Probleem opgelost - zonder wijziging van applicatiecode.
Een woord van waarschuwing: in Microsoft SQL-Server werkt dit niet als u een tabel hebt die naar zichzelf verwijst. Dus als u probeert een delete-cascade op een recursieve boomstructuur te definiëren, zoals hier:
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
het zal niet werken, omdat Microsoft-SQL-server u niet toestaat om een externe sleutel in te stellen bij ON DELETE CASCADE
op een recursieve boomstructuur. Een reden hiervoor is dat de boom mogelijk cyclisch is en dat dit mogelijk tot een impasse zou leiden.
PostgreSQL daarentegen kan dit;
de vereiste is dat de boom niet-cyclisch is.
Als de boom cyclisch is, krijgt u een runtime-fout.
In dat geval hoeft u alleen de verwijderfunctie zelf te implementeren.
Een woord van waarschuwing:
Dit betekent dat u de clienttabel niet meer eenvoudigweg kunt verwijderen en opnieuw kunt invoegen, want als u dit doet, worden alle vermeldingen in "T_Room" verwijderd ... (geen niet-delta-updates meer)