Una chiave esterna può essere NULL e / o duplicata?


325

Per favore chiarisci due cose per me:

  1. Una chiave esterna può essere NULL?
  2. È possibile duplicare una chiave esterna?

Per quanto ne sappia, NULLnon dovrebbe essere usato in chiavi esterne, ma in alcune mie applicazioni sono in grado di inserire NULLsia Oracle che SQL Server, e non so perché.


1
@Adrian: La mia conoscenza della chiave esterna non può essere nulla ma sta prendendo null in SQL Server e Oracle. puoi spiegare perché?
marmellate

@Jams: leggi il link nella mia risposta.
JNK,

11
questo non può essere cancellato perché le risposte e la domanda sono utili. Sentiti libero di modificare la domanda per migliorarla.
Jeff Atwood,

Si prega di dividere la domanda sui duplicati. Di seguito viene data risposta solo a quella relativa ai NULL.
reinierpost,

Risposte:


529

Risposta breve: Sì, può essere NULL o duplicato.

Voglio spiegare perché una chiave esterna potrebbe aver bisogno di essere nulla o potrebbe essere unica o non unica. Ricorda innanzitutto che una chiave esterna richiede semplicemente che il valore in quel campo debba esistere prima in una tabella diversa (la tabella padre). Questo è tutto ciò che un FK è per definizione. Nulla per definizione non è un valore. Null significa che non sappiamo ancora quale sia il valore.

Lascia che ti dia un esempio di vita reale. Supponiamo di avere un database che memorizza le proposte di vendita. Supponiamo inoltre che a ciascuna proposta sia assegnato un solo venditore e un cliente. Quindi la tabella della proposta avrebbe due chiavi esterne, una con l'ID cliente e una con l'ID rappresentante di vendita. Tuttavia, al momento della creazione del record, non viene sempre assegnato un rappresentante di vendita (poiché nessuno è ancora libero di lavorarci), quindi l'ID cliente viene compilato ma l'ID del rappresentante di vendita potrebbe essere nullo. In altre parole, in genere è necessario disporre di un FK null quando è possibile che non si conosca il valore al momento dell'inserimento dei dati, ma si conoscono altri valori nella tabella che devono essere immessi. Per consentire i null in un FK generalmente tutto ciò che devi fare è consentire i null sul campo che ha l'FK. Il valore null è separato dall'idea che sia un FK.

Che sia univoco o meno univoco si riferisce al fatto che la tabella abbia una relazione uno-uno o uno-molti con la tabella padre. Ora, se hai una relazione one-one, è possibile che tu possa avere tutti i dati in una tabella, ma se la tabella si sta allargando troppo o se i dati sono su un argomento diverso (l'impiegato - esempio di assicurazione @tbone ha dato per esempio), quindi si desidera tabelle separate con un FK. Si vorrebbe quindi rendere questo FK o anche il PK (che garantisce l'univocità) o porre un vincolo univoco su di esso.

La maggior parte degli FK è destinata a una o più relazioni ed è ciò che si ottiene da un FK senza aggiungere un ulteriore vincolo sul campo. Quindi, ad esempio, hai una tabella degli ordini e la tabella dei dettagli dell'ordine. Se il cliente ordina dieci articoli contemporaneamente, ha un record ordine e dieci dettagli ordine che contengono lo stesso ID ordine dell'FK.


13
Quindi è meglio che avere un falso venditore chiamato "Non assegnato"?
Thomas Weller,

8
Un commento. I null lasciano molto spazio agli errori nella query da parte di persone che non sanno come SQL (mis) gestisca 3VL. Se un addetto alle vendite non è veramente necessario per una certa tabella r, semplicemente non includi quel record. Una tabella separata può essere "ProposAssignedTo" o una parte del genere, con vincoli appropriati. Un autore di query può quindi unirsi a quella tabella e fornire la propria logica per tutto ciò che vogliamo fare quando una proposta non ha un venditore. NULL non significa semplicemente "non lo sappiamo" - può essere usato per molte cose (motivo per cui è quasi sempre una cattiva idea)
N West

26
@nest, non permetto alle persone che sono incompetenti di interrogare i miei database e qualsiasi sviluppatore che non sa come gestire i null è incompetente. Ci sono momenti in cui i dati non sono noti al momento dell'inserimento iniziale dei dati per un determinato campo ma gli altri campi sono necessari in quel momento.
HLGEM,

28
@ThomasWeller Fare riferimento a un falso venditore ("Non assegnato") aggrava il problema. Presumo che la tabella del tuo venditore abbia più colonne ...? Quale numero di previdenza sociale del signor Unassigned? A quale dipartimento è assegnato? Chi è il suo capo? Spero che tu ottenga il mio punto: quando crei un venditore "Non assegnato" scopri rapidamente che hai scambiato NULLuna tabella per più messaggi NULLin una tabella diversa.
Gili,

1
@ThomasWeller Avrai anche un problema se / quando devi localizzare la tua interfaccia.
tobiv


45

Dalla bocca del cavallo:

Le chiavi esterne consentono valori chiave tutti NULL, anche se non esistono chiavi PRIMARY o UNIQUE corrispondenti

Nessun vincolo sulla chiave esterna

Quando non sono definiti altri vincoli sulla chiave esterna, qualsiasi numero di righe nella tabella figlio può fare riferimento allo stesso valore della chiave principale. Questo modello consente null nella chiave esterna. ...

Vincolo NOT NULL sulla chiave esterna

Quando i valori null non sono consentiti in una chiave esterna, ogni riga nella tabella figlio deve fare esplicito riferimento a un valore nella chiave principale poiché i valori null non sono consentiti nella chiave esterna.

Qualsiasi numero di righe nella tabella figlio può fare riferimento allo stesso valore della chiave principale, quindi questo modello stabilisce una relazione uno-a-molti tra la chiave principale e quella esterna. Tuttavia, ogni riga nella tabella figlio deve avere un riferimento a un valore chiave principale; l'assenza di un valore (un null) nella chiave esterna non è consentita. Lo stesso esempio nella sezione precedente può essere usato per illustrare tale relazione. Tuttavia, in questo caso, i dipendenti devono avere un riferimento a un reparto specifico.

Vincolo UNICO sulla chiave esterna

Quando viene definito un vincolo UNIQUE sulla chiave esterna, solo una riga nella tabella figlio può fare riferimento a un determinato valore di chiave padre. Questo modello consente null nella chiave esterna.

Questo modello stabilisce una relazione uno a uno tra la chiave principale e quella esterna che consente valori indeterminati (null) nella chiave esterna. Ad esempio, supponiamo che la tabella dei dipendenti contenga una colonna denominata MEMBERNO, che fa riferimento a un numero di iscrizione dei dipendenti nel piano assicurativo aziendale. Inoltre, una tabella denominata INSURANCE ha una chiave primaria denominata MEMBERNO e altre colonne della tabella conservano le rispettive informazioni relative a una polizza assicurativa per i dipendenti. MEMBERNO nella tabella dei dipendenti deve essere sia una chiave esterna che una chiave univoca:

  • Per applicare le regole di integrità referenziale tra le tabelle EMP_TAB e INSURANCE (il vincolo FOREIGN KEY)

  • Per garantire che ogni dipendente abbia un numero di abbonamento univoco (il vincolo chiave UNICO)

Vincoli UNICI e NON NULL sulla chiave esterna

Quando sulla chiave esterna sono definiti sia i vincoli UNIQUE che NOT NULL, solo una riga nella tabella figlio può fare riferimento a un determinato valore della chiave padre e poiché i valori NULL non sono consentiti nella chiave esterna, ogni riga nella tabella figlio deve fare esplicito riferimento un valore nella chiave principale.

Guarda questo:

Collegamento Oracle 11g


16

Sì, la chiave esterna può essere nulla come detto sopra dai programmatori senior ... Aggiungerei un altro scenario in cui la chiave esterna dovrà essere nulla .... supponiamo di avere tabelle commenti, immagini e video in un'applicazione che consente commenti su immagini e video. Nella tabella dei commenti possiamo avere due Picture ID di chiavi esterne e VideoId insieme all'Idea di commento chiave primaria. Quindi, quando si commenta un video, sarebbe necessario solo VideoId e pictureId sarebbe nullo ... e se si commentasse una foto, sarebbe necessario solo PictureId e VideosId sarebbe nullo ...


1
Penso che ci sia un modo migliore per risolvere questo problema. Invece di creare nuove colonne, puoi avere due colonne, vale a dire "id" e "type", che conterranno l'id e il nome della tabella delle chiavi esterne. Ad esempio, id = 1, type = Picture rappresenterà il collegamento alla tabella Picture con ID 1. Il vantaggio di utilizzare questa soluzione è che non sarà necessario creare nuove colonne quando i commenti vengono aggiunti a tabelle aggiuntive. Lo svantaggio non sarà un vincolo di chiave esterna a livello di db, ma il vincolo dovrà essere a livello di app.
Agent47DarkSoul,

4
@Agent: abbiamo avuto questa "soluzione" nell'utilizzo della produzione. Non farlo, è terribile. Fare domande diventa questo casino di "se è di tipo 1, unisciti a questa tabella, altrimenti unisciti a questa". È stato un incubo per noi. Abbiamo finito per fare ciò che dice questa risposta e abbiamo creato una nuova colonna per ogni tipo di join. La creazione di colonne è economica. Praticamente solo il difetto è che molte colonne rendono Toad difficile da usare, ma è solo un difetto di Toad.
user128216

1
@FighterJet Rails offre un ottimo framework ORM che gestisce anche query complesse con questa soluzione.
Agent47DarkSoul

2
@Agent: forse può ... ma se riesci a renderlo semplice, perché renderlo complesso? E forse "incubo" era la parola sbagliata da usare: era solo molto scomodo. Non abbiamo sofferto di problemi di integrità dei dati (molto).
user128216

7

dipende dal ruolo che questo foreign keysvolge nella tua relazione.

  1. se anche questa foreign keyè una key attributerelazione, non può essere NULL
  2. se questo foreign keyè un normale attributo nella tua relazione, allora può essere NULL.

3

Ecco un esempio usando la sintassi Oracle: per
prima cosa creiamo una tabella COUNTRY

CREATE TABLE TBL_COUNTRY ( COUNTRY_ID VARCHAR2 (50) NOT NULL ) ;
ALTER TABLE TBL_COUNTRY ADD CONSTRAINT COUNTRY_PK PRIMARY KEY ( COUNTRY_ID ) ;

Crea la tabella PROVINCE

CREATE TABLE TBL_PROVINCE(
PROVINCE_ID VARCHAR2 (50) NOT NULL ,
COUNTRY_ID  VARCHAR2 (50)
);
ALTER TABLE TBL_PROVINCE ADD CONSTRAINT PROVINCE_PK PRIMARY KEY ( PROVINCE_ID ) ;
ALTER TABLE TBL_PROVINCE ADD CONSTRAINT PROVINCE_COUNTRY_FK FOREIGN KEY ( COUNTRY_ID ) REFERENCES TBL_COUNTRY ( COUNTRY_ID ) ;

Questo funziona perfettamente su Oracle. Si noti che la chiave esterna COUNTRY_ID nella seconda tabella non ha "NOT NULL".

Ora per inserire una riga nella tabella PROVINCE, è sufficiente specificare solo PROVINCE_ID. Tuttavia, se hai scelto di specificare anche COUNTRY_ID, deve esistere già nella tabella COUNTRY.


1

Per impostazione predefinita non ci sono vincoli sulla chiave esterna, la chiave esterna può essere nulla e duplicata.

durante la creazione di una tabella / la modifica della tabella, se si aggiunge un vincolo di unicità o non null, solo ciò non consentirà i valori null / duplicati.


0

In parole semplici, le relazioni "Non identificative" tra Entità fanno parte del modello ER ed è disponibile in Microsoft Visio durante la progettazione di ER-Diagram. Ciò è necessario per imporre la cardinalità tra entità di tipo "zero o più di zero" o "zero o uno". Nota questo "zero" in cardinalità invece di "uno" in "uno a molti".

Ora, un esempio di relazione non identificativa in cui la cardinalità può essere "zero" (non identificativo) è quando diciamo che un record / oggetto in un'entità-A "può" o "non può" avere un valore come riferimento al record / s in un'altra entità-B.

Poiché esiste la possibilità che un record dell'entità A si identifichi con i record dell'altra entità B, pertanto dovrebbe esserci una colonna in Entità B per avere il valore identitario del record dell'entità B. Questa colonna può essere "Null" se nessun record in Entity-A identifica il record / i (o, oggetto / i) in Entity-B.

Nel paradigma orientato agli oggetti (mondo reale), ci sono situazioni in cui un oggetto di classe B non dipende necessariamente (fortemente accoppiato) dall'oggetto di classe A per la sua esistenza, il che significa che la classe B è liberamente accoppiata con la classe- A tale che la Classe A può "contenere" (Contenimento) un oggetto di Classe A, in contrapposizione al concetto di oggetto di Classe B deve avere (Composizione) un oggetto di Classe A, per il suo (oggetto di classe- B) creazione.

Dal punto di vista della query SQL, è possibile eseguire una query su tutti i record nell'entità-B che sono "non nulli" per la chiave esterna riservata all'entità-B. Ciò porterà tutti i record con un determinato valore corrispondente per le righe in Entity-A, in alternativa tutti i record con valore Null saranno i record che non hanno alcun record in Entity-A in Entity-B.


-1

Penso che sia meglio considerare la possibile cardinalità che abbiamo nei tavoli. Possiamo avere zero cardinalità minima possibile. Quando è facoltativo, la partecipazione minima delle tuple dalla tabella correlata potrebbe essere zero, Ora si affronta la necessità di consentire che i valori della chiave esterna siano nulli.

Ma la risposta è che tutto dipende dall'azienda.


-3

L'idea di una chiave esterna si basa sul concetto di fare riferimento a un valore già esistente nella tabella principale. Ecco perché si chiama una chiave esterna nell'altra tabella. Questo concetto si chiama integrità referenziale. Se una chiave esterna viene dichiarata come campo nullo, violerà la logica stessa dell'integrità referenziale. A cosa si riferirà? Può fare riferimento solo a qualcosa presente nella tabella principale. Quindi, penso che sarebbe sbagliato dichiarare nullo un campo chiave esterna.


Può fare riferimento a "niente" o non conosci ancora il suo valore NULL, ma ciò che dice l'integrità referenziale è che se fa riferimento a "qualcosa" deve essere lì.
yaxe,

-7

Penso che la chiave esterna di una tabella sia anche la chiave primaria di un'altra tabella, quindi non consente null. Quindi non c'è dubbio di avere un valore null nella chiave esterna.

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.