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)



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow