È possibile vincolare una tabella per avere un valore in una sola di una serie di colonne

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

Domanda

Ho una tabella che deve collegare una delle tre tabelle separate, ma dovrebbe collegarsi solo a una di esse, ad esempio

Main_Table
id UNIQUEIDENTIFIER
t1_id UNIQUEIDENTIFIER
t2_id INT
t3_id INT

T1
id UNIQUEIDENTIFIER
name VARCHAR(255)

T2
id INT
name VARCHAR(255)

T3
id INT
name VARCHAR(255)

È possibile avere un vincolo per cui solo uno di t1, t2 o t3 non è nullo per volta?

Questo è solo un cattivo design? In tal caso, quali suggerimenti daresti per il design?

Modifica

Mi è stato chiesto di elaborare le ragioni alla base di questo particolare design.

Main_Table sta tentando di essere una tabella dei pagatori, che potrebbe fare riferimento a un singolo utente (T1), un gruppo di singoli utenti (T2) o un gruppo di gruppi (T3).

Questo è un progetto di database che ho ereditato e purtroppo non è soggetto a modifiche.

Il mio problema più grande è che devo associare tra tipi diversi, quindi un campo di tipo non funzionerà qui poiché gli indici sono diversi.

È stato utile?

Soluzione

Il disegno che stai descrivendo si chiama archi esclusivi . Sì, è un design piuttosto fragile e fallisce persino alcune regole di normalizzazione.

Ecco un'alternativa:

Main_Table
id UNIQUEIDENTIFIER
t_id INT NOT NULL
  FOREIGN KEY (t_id) REFERENCES T0 (id)

T0
id UNIQUEIDENTIFIER
type INT NOT NULL CHECK (type IN (1,2,3))
  UNIQUE KEY (id, type)

T1
id INT 
type INT NOT NULL CHECK (type = 1) 
name VARCHAR(255)
  FOREIGN KEY (id, type) REFERENCES T0 (id, type)

T2
id INT
type INT NOT NULL CHECK (type = 2)
name VARCHAR(255)
  FOREIGN KEY (id, type) REFERENCES T0 (id, type)

T3
id INT
type INT NOT NULL CHECK (type = 3)
name VARCHAR(255)
  FOREIGN KEY (id, type) REFERENCES T0 (id, type)

Con questo disegno, ogni riga in Main_Table deve fare riferimento a una riga in T0 .
Allo stesso modo, ogni riga in T0 può essere padre di una sola riga in T1 , T2 o T3 .

Questo è un modo per implementare l'ereditarietà delle tabelle di classe e le associazioni polimorfiche senza interrompere l'integrità referenziale.


  

Main_Table sta tentando di essere un pagatore   tabella, che potrebbe fare riferimento a un   singolo utente (T1), un gruppo di   singoli utenti (T2) o un gruppo di   gruppi (T3).

Bene, quindi pensaci in termini di design orientato agli oggetti. Se avessi tre classi che potrebbero fungere da destinatari dei pagamenti, creeresti una interfaccia chiamata Payable o qualcosa del genere, in modo che ognuna possa contare sulla digitazione di quegli oggetti. Tutti gli oggetti Payable devono avere un metodo sendPayment () per esempio. In alcuni linguaggi OO, l'interfaccia è una superclasse ed è chiamata classe astratta o pura classe virtuale .

La tabella T0 funziona come un tipo comune per ciascuna delle tabelle figlio T1 , T2 e T3 . Quando Main_Table ha una chiave esterna per T0 , è come dire Main_Table deve avere un riferimento a qualche entità che è Pagabile , ma qualsiasi oggetto che discende da quella superclasse è accettabile da usare.

La colonna type è solo un trucco per assicurarsi che un dato T0.id possa essere referenziato solo da una tabella di sottoclassi alla volta. È un po 'facoltativo, se puoi fare affidamento sulla logica dell'applicazione per inserire una determinata riga figlio in una sola delle tabelle delle sottoclassi.


Vedi anche la sezione Associazioni polimorfiche nella mia presentazione " SQL Antipatterns Strike Back . "

Altri suggerimenti

Se il tuo DB ha vincoli di controllo, potresti generare un brutto kludge come:

ALTER TABLE Main_Table
 add constraint CK_ThisWorksButItsUgly
  check ( (  case when t1_id is null then 0 else 1 end
           + case when t2_id is null then 0 else 1 end
           + case when t3_id is null then 0 else 1 end) = 1)

Alcune sintassi potrebbero essere errate lì, ma hai capito. Probabilmente avrebbe funzionato abbastanza bene - il controllo avrebbe dovuto sparare solo quando una delle colonne fosse stata modificata - ma in nessun modo è carina.

Gli archi esclusivi di Bill Karwin sono fantastici, se puoi riprogettare il design del database.

oltre al cattivo design, se non puoi cambiarlo, è possibile usare un trigger per applicare questo vincolo

Questa è l'ennesima istanza del modello gen-spec.

Vai a articoli web su " specializzazione generalizzazione modellistica relazionale " ;. Ce ne sono alcuni eccellenti là fuori.

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