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)



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow