Domanda

Sto lavorando su un database che tiene traccia dei file e delle dipendenze nei progetti. In breve, ho due tavoli principali; la tabella PROJECTS elenca i nomi dei progetti e altre proprietà, la tabella FILES elenca i file. Ogni voce di file punta a un progetto come chiave esterna impostata su CASCADE, quindi se elimino un record di progetto dal database, scompaiono anche tutti i record di file. Fin qui tutto bene.

Ora ho una tabella DEPENDENCIES aggiuntiva. Ogni record nella tabella delle dipendenze è di due file, specificando che il primo file dipende dal secondo. Anche in questo caso si tratta di chiavi esterne, la prima è impostata su CASCADE (quindi se elimino una voce di file, questo record viene eliminato), ma la seconda è impostata su RESTRICT (quindi non sono autorizzato a eliminare una voce di file se qualsiasi altro file dipende su di esso). Ancora una volta, tutto sembra a posto.

Sfortunatamente sembra che non riesca più a cancellare un progetto con una singola istruzione di eliminazione SQL! L'eliminazione tenta di eliminare in cascata i file, ma se uno di questi appare nella tabella DEPENDENCIES, la chiave esterna RESTRICT impedisce l'eliminazione (anche se quel record nella tabella delle dipendenze verrà rimosso perché l'altra colonna è CASCADE). L'unica soluzione che ho è calcolare un ordine esatto per eliminare i file in modo che nessuno dei vincoli dei record di dipendenza venga violato e rimuovere i record di file uno alla volta prima di tentare di rimuovere il progetto.

Esiste un modo per impostare il mio schema di database in modo che una singola eliminazione SQL dalla tabella dei progetti esegua correttamente il collegamento a cascata delle altre eliminazioni? Sto usando Firebird 2.1, ma non so se questo possa fare la differenza - sembra che dovrebbe esserci un modo per farlo funzionare?

È stato utile?

Soluzione

Non puoi controllare l'ordine di cancellazione tramite una chiave esterna a cascata, ma potresti essere in grado di progettare un trigger su PROJECTS per eliminare le righe in FILES che appartengono a questo progetto e sono anche elencate in <= > come dipendente da altri DEPENDENCIES. Rendilo un BEFORE DELETE trigger, quindi dovrebbe essere eseguito prima degli effetti a cascata.

Qualcosa del genere:

CREATE TRIGGER Del_Child_Files FOR PROJECTS
BEFORE INSERT
AS BEGIN
  FOR SELECT F.FILE_ID FROM FILES F JOIN DEPENDENCIES D 
      ON F.FILE_ID = D.CHILD_ID
    WHERE F.PROJECT_ID = OLD.PROJECT_ID
    INTO :file_id
  DO
    DELETE FROM FILES WHERE FILE_ID = :file_id;
  DONE
END

Quindi quando si elimina un progetto, questo elimina tutte le " child " file di un progetto che dipendono da altri file e ciò si elimina per eliminare le righe in <=> in modo che tutti i file rimanenti siano liberi da dipendenze. La tua eliminazione del progetto ora può essere a cascata per eliminare questi file.

Non l'ho provato e la mia sintassi di Firebird potrebbe essere arrugginita, ma forse ti farà iniziare.

Ovviamente, prova questo su una copia dei tuoi dati, non sui dati in tempo reale!

Altri suggerimenti

Il sistema supporta i vincoli differiti, in cui il controllo dei vincoli può essere rinviato fino a un punto di commit?

Forse è solo una cosa di Oracle.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top