Nullable Foreign Key cattiva pratica?


114

Supponiamo che tu abbia una tabella Ordini con una chiave esterna per un ID cliente. Ora, supponi di voler aggiungere un ordine senza un ID cliente, (se ciò dovrebbe essere possibile è un'altra domanda) dovresti rendere la chiave esterna NULL ... È una cattiva pratica o preferiresti lavorare con una tabella di collegamento tra Ordini e clienti? Sebbene la relazione sia da 1 a n, una tabella di collegamento lo renderebbe da n a n. D'altra parte, con una tabella di collegamento, non ho più quei NULL ...

In realtà non ci saranno molti NULL nel database, perché un record con una chiave esterna a NULL è solo temporaneamente fino a quando non viene aggiunto un cliente per l'ordine.

(Nel mio caso non è un ordine e un cliente).

EDIT: Che dire di un cliente non assegnato a cui collegarsi?


9
Questo è uno degli scopi principali di avere NULL disponibili in uno schema di database. Inoltre, questo è il motivo per cui puoi dichiarare i campi NULL o NOT NULL, in modo che i requisiti specifici del tuo schema possano essere soddisfatti.
gahooa

7
Inizialmente ho letto la domanda come chiavi primarie nullable , e stavo per entrare con qualche consiglio forte ... :-)
Andrzej Doyle

Risposte:


51

Avere la tabella dei collegamenti è probabilmente un'opzione migliore. Almeno non viola la normalizzazione BCNF (forma normale Boyce-Codd). tuttavia preferirei essere pragmatico. Se hai pochissimi di questi valori nulli e sono solo temporanei, penso che dovresti saltare la tabella dei collegamenti poiché aggiunge solo complessità allo schema.

In una nota a margine; l'utilizzo di una tabella di collegamento non lo rende necessariamente da n ad n, se nella tabella di collegamento si utilizza la chiave esterna che punta alla tabella degli ordini come chiave primaria in quella tabella di collegamento, la relazione è ancora 1..n. Può esserci solo una voce in quella tabella di collegamento per ordine.


2
source__destination_link o SourceDestination
Svisstack

7
Sarei interessato a conoscere una situazione in cui avere una tabella di collegamento è migliore, non mi sono mai imbattuto in una situazione in cui avrebbe migliorato il flusso del processo in alcun modo.
Reimius

5
Come sottolineato nella mia risposta, in questo caso specifico sarei pragmatico e non utilizzerei una tabella di collegamento. Sono sicuro che le forme normali non sono state inventate per migliorare il flusso del processo, ma piuttosto per garantire la coerenza ed evitare la ridondanza. Tuttavia, è una discussione molto generale, penso che debba essere vista caso per caso.
Patrik Hägne

110

No Non c'è niente di sbagliato con Nullable FKs. Ciò è comune quando l'entità a cui punta FK è in una relazione (zero o uno) con (1 o molti) con la tabella di riferimento chiave primaria.

Un esempio potrebbe essere se avessi sia un indirizzo fisico che un attributo indirizzo postale (colonna) in una tabella, con FK in una tabella indirizzi. È possibile rendere annullabile l'indirizzo fisico da gestire quando l'entità ha solo una casella postale (indirizzo postale) e l'indirizzo postale annullabile da gestire quando l'indirizzo postale è uguale all'indirizzo fisico (o meno).


39

Le colonne nullable possono essere da 1NF a 5NF, ma non in 6NF secondo quanto ho letto.

Solo se sai meglio di Chris Date "cosa significa veramente la prima forma normale". Se x e y sono entrambi nullable, e in effetti in alcune righe x e y sono entrambi null, allora WHERE x=ynon produce true. Ciò dimostra oltre ogni ragionevole dubbio che null non è un valore (perché qualsiasi valore reale è sempre uguale a se stesso). E poiché l'RM prescrive che "deve esserci un valore in ogni cella di una tabella", qualsiasi cosa che possibilmente contiene valori nulli, non è una cosa relazionale, e quindi la questione di 1NF non si pone nemmeno.

Ho sentito dire che le colonne nullable in generale interrompono il primo grado di normalizzazione.

Vedi sopra per il valido motivo alla base di tale argomento.

Ma in pratica è molto pratico.

Solo se sei immune al mal di testa che di solito provoca in tutto il resto del mondo. Uno di questi problemi (ed è solo un problema minore, rispetto ad altri nullfenomeni) è il fatto che WHERE x=yin SQL significa effettivamente WHERE x is not null and y is not null and x=y, ma che la maggior parte dei programmatori semplicemente non ne è a conoscenza e si limita a leggerlo. A volte senza alcun danno, altre volte no.

In effetti, le colonne nullable violano una delle regole di progettazione del database più fondamentali: non combinare elementi di informazione distinti in una colonna. I valori Null fanno esattamente questo perché combinano il valore booleano "questo campo è / non è realmente presente" con il valore effettivo.


18
+1 per "DOVE x non è nullo ey non è nullo e x = y". Non ne ero consapevole.
RobM

1
Argomenti ed esempi molto ben strutturati.
pedz

1
Un problema. Quando il valore "non esiste" (che È uno scenario del mondo reale) e l'attributo del database non consente valori nulli, qualunque valore sia nell'attributo è SBAGLIATO. Per quanto riguarda il mal di testa, ricorda, KISS, non significa solo mantenerlo semplice, significa mantenerlo il più semplice possibile, ma non più semplice. Se il "modello relazionale" richiede un risultato non realistico e stupido, allora forse le regole devono espandersi per gestire i dati del mondo reale necessari?
Charles Bretana

1
È stato dimostrato che una logica a tre valori porta alla necessità di una logica a quattro valori e ciò porta alla necessità di una logica a cinque valori, ecc. Ecc. La logica a due valori è sufficiente, ma le strutture dati che otteniamo quando applicandolo rendiamo "il più semplice possibile" ancora molto meno semplice di "semplice come vorremmo".
Erwin Smout

2
Chris Date, Logic & Databases, Capitolo 6, "Perché la logica del DBMS relazionale non deve avere molti valori", pag 145. Anche l'elenco dei riferimenti a quel capitolo dovrebbe essere interessante, specialmente quelli che riguardano McGoveran.
Erwin Smout

13

Non riesco a vedere nulla di sbagliato in questo è solo una relazione n-1 opzionale che verrà rappresentata con un valore nullo nella chiave esterna. Altrimenti se metti la tua tabella dei link dovrai fare in modo che non diventi una relazione nn, causando così ancora più problemi.


2
In realtà è una relazione 0-N, non una relazione 1-N opzionale. Ma sono d'accordo con te.
Eric J.

5
Gestire? È un semplice vincolo UNICO sul lato 0 a 1!
wqw

2
Sì, è un vincolo UNICO, ma dovrai anche occuparti di eventuali eccezioni in seguito nel tuo codice a causa di quel vincolo ...
pedromarce

4

Le relazioni opzionali sono sicuramente possibili nel modello relazionale.

È possibile utilizzare valori nulli per esprimere l'assenza di una relazione. Sono convenienti, ma ti causeranno gli stessi mal di testa che i nulli ti causano altrove. Un posto in cui non causano problemi è l'unione. Le righe che hanno un null nella chiave esterna non corrispondono ad alcuna riga nella tabella di riferimento. Quindi abbandonano un inner join. Se esegui join esterni, avrai comunque a che fare con i null.

Se vuoi davvero evitare i valori nulli (6a forma normale), puoi scomporre la tabella. Una delle due tabelle scomposte ha due colonne di chiavi esterne. Una è la chiave esterna facoltativa che hai e l'altra è una chiave esterna che fa riferimento alla chiave primaria della tabella originale. Ora devi usare i vincoli per evitare che la relazione diventi molti-a-molti, se vuoi impedirlo.


2

Usare NULL sarebbe un buon modo per ripulire gli ordini incompleti:

SELECT * FROM `orders`
WHERE `started_time` < (UNIX_TIMESTAMP() + 900) AND `customer_id` IS NULL

Quanto sopra mostrerebbe gli ordini più vecchi di 15 minuti senza un ID cliente correlato.


1

Se stai solo aggiungendo l'ordine temporaneamente senza ID cliente fino a quando non viene definito un cliente, non sarebbe più semplice aggiungere il cliente e l'ordine in una singola transazione, eliminando così la necessità di inserire la chiave esterna NULL ed evitando qualsiasi vincolo o trigger hai impostato essere violato?

Normalmente questa situazione si verifica nelle app web in cui l'ordine è dettagliato prima che il cliente definisca chi è. E in queste situazioni l'ordine viene mantenuto nello stato del server o in un cookie finché non viene fornito tutto lo stato necessario per un ordine completo, a quel punto l'ordine viene mantenuto nel database.

Le chiavi esterne NULL vanno bene per cose come gli indirizzi, come menzionato sopra. Ma un campo cliente NULL non ha senso per un ordine e dovrebbe essere vincolato.


Il cliente dell'ordine era un esempio. Nella mia app è più simile agli indirizzi. Impossibile trovare immediatamente un esempio corretto fino in fondo. grazie.
Lieven Cardoen

1
Questo potrebbe essere uno scenario valido se il database fosse utilizzato per memorizzare gli articoli in un carrello degli acquisti, dove il carrello degli acquisti non appartiene a un utente registrato.
Johnie Karr

1

Puoi sempre aggiungere una riga artificiale alla tua tabella Customer, qualcosa come Id = -1 e CustomerName = 'Unknown' e quindi, nei casi in cui normalmente imposti il ​​tuo CustomerId in Order NULL, impostalo su -1.

Ciò ti consente di non avere FK nullable ma rappresenta comunque la mancanza di dati in modo appropriato (e ti salverà dagli utenti a valle che non sanno come trattare i NULL).


Solo per aggiungere a questo, ricorda che i NULL non vengono memorizzati in un indice (in Oracle), quindi questo significa che avrebbe senso saltare la tabella dei collegamenti e scegliere il nullable FK - dal punto di vista delle prestazioni. L'altra altra cosa da cui potrebbe dipendere è se si desidera memorizzare qualcos'altro in questa tabella dei collegamenti, ad esempio, CHI ha creato il collegamento e quando? Il collegamento è ora inattivo / cancellato (ma una volta lo era?)
Degno7

Questa è una cattiva idea. Se si dispone di una chiave esterna impostata e i dati a cui punta vengono successivamente rimossi, non si otterrà l'eccezione della chiave esterna e ora i dati sono privi di senso. Peggio ancora, se in seguito viene assegnato qualcos'altro a quella chiave, stai indicando completamente il cliente sbagliato
IcedDante

0

Gli FK nullable per le relazioni molti-a-uno opzionali vanno benissimo.


-1

Ho sentito dire che le colonne nullable in generale interrompono il primo grado di normalizzazione. Ma in pratica è molto pratico.


3
Le colonne nullable possono essere da 1NF a 5NF, ma non in 6NF secondo quanto ho letto.
Walter Mitty

-1

Sì, c'è qualcosa che non va. Non è una chiave esterna se è annullabile. La progettazione del database in base al codice. Forse crei un collegamento zero a non assegnato. o "Non assegnato" se usi un carattere col. Mantieni l'integrità dei tuoi dati al 100%.

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.