SQL
Cascading Radera
Sök…
PÅ RADERA CASCADE
Antag att du har en applikation som administrerar rum.
Antag vidare att din ansökan fungerar per kundbasis (hyresgäst).
Du har flera klienter.
Så din databas kommer att innehålla en tabell för klienter och en för rum.
Nu har varje klient N rum.
Detta bör betyda att du har en utländsk nyckel på ditt rumsbord, med hänvisning till klienttabellen.
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
Förutsatt att en klient går vidare till någon annan programvara måste du ta bort hans data i din programvara. Men om du gör det
DELETE FROM T_Client WHERE CLI_ID = x
Då får du en utländsk nyckelkränkning eftersom du inte kan ta bort klienten när han fortfarande har rum.
Nu skulle du ha skrivkod i din applikation som raderar klientens rum innan den raderar klienten. Anta vidare att i framtiden kommer fler fler utländska nyckelberoende att läggas till i din databas, eftersom din applikations funktionalitet expanderar. Fruktansvärd. För varje ändring i din databas måste du anpassa programmets kod på N platser. Eventuellt måste du också anpassa kod i andra applikationer (t.ex. gränssnitt till andra system).
Det finns en bättre lösning än att göra det i din kod.
Du kan bara lägga till ON DELETE CASCADE
till din utländska nyckel.
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 kan du säga
DELETE FROM T_Client WHERE CLI_ID = x
och rummen tas automatiskt bort när klienten raderas.
Problemet är löst - utan applikationskodändringar.
Ett försiktighetsord: I Microsoft SQL-Server fungerar detta inte om du har en tabell som refererar till sig själv. Så om du försöker definiera en raderingskaskad på en rekursiv trädstruktur, så här:
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
det fungerar inte, eftersom Microsoft-SQL-servern inte låter dig ställa in en utländsk nyckel med ON DELETE CASCADE
på en rekursiv trädstruktur. En anledning till detta är att trädet kanske är cykliskt, och det kan möjligen leda till ett dödläge.
PostgreSQL kan å andra sidan göra detta;
kravet är att trädet är icke-cykliskt.
Om trädet är cykliskt får du ett körtidfel.
I så fall måste du bara implementera borttagningsfunktionen själv.
Ett försiktighetsord:
Detta innebär att du inte bara kan ta bort och sätta in klienttabellen längre, för om du gör det kommer det att ta bort alla poster i "T_Room" ... (inga uppdateringar utan delta mer)