Perché le chiavi esterne composite hanno bisogno di un vincolo univoco separato?


10

Ecco una semplice tabella in cui i record possono fare riferimento a record parent nella stessa tabella:

CREATE TABLE foo (
    id         SERIAL  PRIMARY KEY,
    parent_id  INT     NULL,
    num        INT     NOT NULL,
    txt        TEXT    NULL,
    FOREIGN KEY (parent_id) REFERENCES foo(id)
);

Con il requisito aggiuntivo che uno degli altri valori di campo ( num) deve essere identico tra i record padre e figlio, ho pensato che una chiave esterna composita avrebbe dovuto fare il trucco. Ho cambiato l'ultima riga in

    FOREIGN KEY (parent_id, num) REFERENCES foo(id, num)

e ha ottenuto ERRORE: non esiste un vincolo univoco per la corrispondenza delle chiavi fornite per la tabella referenziata "pippo" .

Posso facilmente aggiungere questo vincolo, ma non capisco perché sia ​​necessario, quando una delle colonne di riferimento ( id) è già garantita come unica? Per come la vedo io, il nuovo vincolo sarebbe ridondante.

Risposte:


11

È una limitazione del DBMS - in tutti loro per quanto ne so. E non solo quando aggiungi una colonna ma anche quando riorganizzi le colonne. Se abbiamo un UNIQUEvincolo su (a1, a2), non possiamo aggiungerne uno a meno FOREIGN KEYche REFERENCES (a2, a1)non ci sia un vincolo univoco su quello (a2, a1)che è essenzialmente ridondante.

Non sarebbe terribilmente difficile aggiungere questo come caratteristica:

Quando è presente un UNIQUEvincolo (a), anche una (a, b, c, ..., z)o più (b,c, ...a, ...z)combinazioni sono garantite UNIQUE.

o la generalizzazione:

Quando è presente un UNIQUEvincolo (a1, a2, ..., aN), (a1, a2, ..., aN, b1, b2, ..., bM)viene garantita anche qualsiasi combinazione o riarrangiamento UNIQUE.

Sembra che non sia stato chiesto o che non sia stato considerato una priorità abbastanza alta per essere implementato.

Puoi sempre fare una richiesta - nel rispettivo canale - per l'implementazione della funzione. O addirittura implementalo tu stesso, se il DBMS è open source, come Postgres.


Non sono sicuro che sarebbe così semplice .. Che dire degli indici parziali o dei valori NULL? ecc. NULL potrebbe comunque funzionare bene se sei soddisfatto NULL != NULL. Comunque .. :)
Joishi Bodio,

@JoishiBodio Non credo che i Null siano un problema. È possibile definire anche vincoli UNICI o colonne nullable. Il valore predefinito è che se una colonna ha un valore NULL, il vincolo viene passato e la riga accettata.
ypercubeᵀᴹ

Al secondo però, se a1, a2, ... aN non sono nullable e b1, b2, bM potremmo avere dei problemi. Ma la funzionalità potrebbe sicuramente essere implementata per colonne non annullabili. Ciò che è probabilmente preoccupante sono le implicazioni sull'efficienza.
ypercubeᵀᴹ

Conosco bene UNIQUE INDEXdove sono le colonne NULLABLE... ed è per questo che l'ho menzionato. :) Ma sono d'accordo - nel caso in cui non ci siano NULL (e nemmeno un indice parziale), è probabilmente abbastanza semplice.
Joishi Bodio,

5

Le chiavi esterne in generale (non solo composte) DEVONO puntare a una chiave unica di qualche tipo in un'altra tabella. In caso contrario, non vi sarebbe integrità dei dati relazionali.

Questo è lamentoso perché, mentre hai una chiave univoca su (id) .. NON hai una chiave univoca su (id, num) .. Pertanto, per quanto riguarda il DB, la coppia (id, num) è non GARANTITO di essere unico. Noi, come umani, possiamo capire che sarà unico, ma sono sicuro che ci sarebbe un sacco di codice aggiuntivo che dovrebbero aggiungere per rendere Postgres abbastanza intelligente da vedere che "oh hey .. id dovrebbe essere unico , quindi id, num dovrebbe anche essere unico "..

Sarei molto sorpreso se aggiungessero quel codice quando tutto ciò che devi fare è creare un altro indice univoco sulle due colonne per risolvere il problema.

Per essere chiari, il codice che dovrebbero aggiungere non sarebbe solo questo semplice caso ... dovrebbe gestire tutti i casi, anche quelli in cui la chiave esterna è su 4+ colonne, ecc. Sono sicuro la logica sarebbe piuttosto complessa.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.