Domanda MySQL - Chiave univoca Non funziona correttamente o sto fraintendendo?
-
07-07-2019 - |
Domanda
Sto cercando di creare una relazione in cui è possibile includere una delle quattro parti diverse, ma qualsiasi raccolta delle stesse parti deve essere gestita come unica.
Esempio: Un incarico deve avere una società assegnata, può eventualmente avere una posizione, un gruppo di lavoro e un programma assegnati. Un incarico potrebbe non avere un gruppo di lavoro senza una posizione.
Supponiamo di avere aziende A, B, C; posizioni X, Y, Z; gruppi di lavoro I, J, K e programmi 1, 2, 3.
Quindi potrebbero essere incluse relazioni valide A - X - I - 1 A - Z - 2 B - Y C C - 3 B - Z - K
Ma includerebbe relazioni non valide A - K (gruppo di lavoro senza posizione) Y - K - 1 (Nessuna azienda)
Quindi, per creare la mia tabella, ho creato
companyID INT NOT NULL,
FOREIGN KEY companyKEY (companyID) REFERENCES company (companyID),
locationID INT,
FOREIGN KEY locationKEY (locationID) REFERENCES location (locationID),
workgroupID INT,
FOREIGN KEY workgroupKEY (workgroupID) REFERENCES workgroup (workgroupID),
programID INT,
FOREIGN KEY programKEY (programID) REFERENCES program (programID),
UNIQUE KEY companyLocationWorkgroupProgramKEY (companyID, locationID, workgroupID, programID)
Immagino che questo gestisca tutte le mie relazioni oltre alla necessità di un incarico di avere una posizione se c'è un gruppo di lavoro (che posso felicemente fare programmaticamente o con trigger, penso)
Tuttavia, quando provo questo schema, mi permette di inserire il seguente ...
INSERT INTO test VALUES (1, null, null, null), (1, null, null, null);
... senza lamentele. Immagino che (1, null, null, null) non sia uguale a se stesso poiché sono inclusi i null. In questo caso, esiste un modo per gestire questa relazione?
Qualsiasi aiuto sarebbe apprezzato!
Soluzione
Questa è una caratteristica (anche se non è quella che mi aspettavo).
Questa discussione suggerisce di rendere la tua chiave una chiave primaria per ottenere il comportamento che ti aspettavi:
Questa è una caratteristica - un valore NULL è un valore indefinito, quindi due NULL i valori non sono gli stessi. Può essere un poco confuso ma ha senso quando ci pensi.
Un indice UNICO lo garantisce i valori non NULL sono univoci; potresti specifica che la tua colonna non accetta Valori NULL.
Altri suggerimenti
L'unico modo in cui posso pensare di gestirlo senza trigger / programmazione aggiuntivi sarebbe quello di avere un unico "Nessuno dei precedenti" valore in ciascuna delle tabelle referenziate, in modo che il test sia simile
INSERT INTO test VALUES (1, NO_LOCATION, NO_WORKGROUP, NO_PROGRAM),
(1, NO_LOCATION, NO_WORKGROUP, NO_PROGRAM)
Dove gli identificatori NO_ *
sono del tipo / lunghezza corretti per le colonne del tuo ID. Ciò fallirebbe, come ti aspetteresti.
In MySQL NULL! = NULL o altro. Questo è ciò che UNIQUE non funziona. Dovresti usare un altro valore predefinito per gli spazi, come zero
Penso che sia importante notare che esiste un modo adeguato per interpretare e gestire i valori NULL, e il comportamento mostrato dall'OP è esattamente ciò che si intende. Puoi ignorare quel comportamento e puoi gestire la tua domanda come vuoi senza obiezioni da parte mia, ma potrebbe essere bene " Accetta " una risposta che descrive una qualche forma di Best Practices, piuttosto che una preferenza personale non standard.
O se non sei d'accordo con la Best Practice di consenso, non puoi semplicemente accettare alcuna risposta.
Non è una corsa per ottenere una risposta accettata il più rapidamente possibile. La delibera e la collaborazione intendono anche far parte del processo, credo.