Modellazione dei dati: che cos'è una buona progettazione relazionale quando una tabella ha diversi vincoli di chiave esterna a una singola tabella?

StackOverflow https://stackoverflow.com/questions/432320

  •  08-07-2019
  •  | 
  •  

Domanda

Ho 2 tabelle: 1. Dipendenti 2. Buoni

La tabella Employees ha una sola chiave primaria. La tabella dei voucher presenta 3 vincoli di chiave esterna che fanno riferimento alla tabella Employees.

Di seguito è riportato uno script T-SQL di esempio (non lo script di tabella effettivo) per creare entrambe le tabelle e la loro relazione in SQL Server:

IF OBJECT_ID('dbo.Vouchers') IS NOT NULL
    DROP TABLE dbo.Vouchers
IF OBJECT_ID('dbo.Employees') IS NOT NULL
    DROP TABLE dbo.Employees
GO

CREATE TABLE Employees
(
  ObjectID     INT    NOT NULL   PRIMARY KEY    IDENTITY
)

CREATE TABLE Vouchers
(
  ObjectID     INT    NOT NULL   PRIMARY KEY    IDENTITY,
  IssuedBy     INT,
  ReceivedBy   INT,
  ApprovedBy   INT,

  CONSTRAINT fk_Vouchers_Employees_IssuedBy FOREIGN KEY (IssuedBy)
                                    REFERENCES Employees (ObjectID)
                                    ON UPDATE CASCADE
                                    ON DELETE NO ACTION,
 CONSTRAINT fk_Vouchers_Employees_ReceivedBy FOREIGN KEY (ReceivedBy)
                                    REFERENCES Employees (ObjectID)
                                    ON UPDATE CASCADE
                                    ON DELETE NO ACTION,
 CONSTRAINT fk_Vouchers_Employees_ApprovedBy FOREIGN KEY (ApprovedBy)
                                    REFERENCES Employees (ObjectID)
                                    ON UPDATE CASCADE
                                    ON DELETE NO ACTION 
)

Ma viene generato un errore:

Msg 1785, Level 16, State 0, Line 7
Introducing FOREIGN KEY constraint 'fk_Vouchers_Employees_ReceivedBy' on table 'Vouchers' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.

Non ho idea di quale soluzione efficiente sia disponibile qui. I requisiti sulla relazione sono: ogni volta che un Dipendente viene eliminato, il Voucher che fa riferimento al Dipendente di alcune delle sue colonne non viene eliminato (ON DELETE CASCADE non è un'opzione). Invece, i valori delle colonne (IssuedBy, ReceivedBy e / o ApprovedBy) che fanno riferimento al Dipendente eliminato devono essere impostati su NULL (poiché le colonne sono NULLABLE).

Mille grazie!

È stato utile?

Soluzione

Dal punto di vista della progettazione relazionale, la tabella dei voucher è composta da tre chiavi esterne. Indipendentemente dal fatto che tu scelga di applicarli, attraverso asserzioni CASCADE o altro, è un problema di implementazione, ma esiste ancora il design relazionale. Presumibilmente vuoi imporre che, se uno dei tre campi non è NULL, allora deve esistere un record corrispondente. O no. È un problema di implementazione per stabilire se ti interessa applicare il progetto.

Tuttavia, le violazioni che descrivi sono assunte a tuo rischio e pericolo. Il fatto che stai ponendo questa domanda suggerisce che potresti non apprezzare appieno tutti i modi in cui queste scelte possono portare alla palude.

Penso che l'errore possa essere una conseguenza del fatto che più di uno dei tre potrebbe riferirsi allo stesso dipendente.

A proposito, in pochissimi casi ho mai trovato necessario eliminare i record in modo tale che CASCADES fosse utile. Di solito questo sarebbe usato per evitare che il database fosse troppo grande; e la capacità del database è sempre meno un problema nel tempo.

Altri suggerimenti

In realtà non eliminerei i dipendenti, ma utilizzerei invece un trigger per impostare un flag per contrassegnarli come eliminati.

In genere non attivo cascata di aggiornamenti o eliminazioni, ma invece richiedo un'applicazione per eseguire esplicitamente queste azioni.

Dal punto di vista del design, sembra buono avere le 3 chiavi esterne che hai elencato. Sembra che il messaggio di errore che stai ricevendo sia relativo alle opzioni ON UPDATE CASCADE sulle tue chiavi esterne (anche se sono stato in grado di creare la tabella come specificato). Indipendentemente da ciò, per ottenere il comportamento di cui parli di voler, consiglierei un trigger sulla tabella Employees, che si attiva prima di eliminare il record. Questo trigger trova le istanze di Employees.OjbectID nella tabella dei voucher e le imposta su NULL.

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