Question MySQL - Clé unique Ne fonctionne pas correctement ou suis-je mal compris?
-
07-07-2019 - |
Question
J'essaie de créer une relation dans laquelle quatre parties différentes peuvent être incluses, mais toute collection des mêmes parties doit être traitée comme unique.
Exemple: Une affectation doit avoir une entreprise affectée, peut éventuellement avoir un emplacement, un groupe de travail et un programme assignés. Une affectation ne peut pas avoir un groupe de travail sans emplacement.
Supposons que nous ayons des sociétés A, B, C; les emplacements X, Y, Z; groupes de travail I, J, K et programmes 1, 2, 3.
Les relations valides pourraient donc inclure A - X - I - 1 A - Z - 2 PAR C C - 3 B - Z - K
Mais les relations invalides incluraient A - K (Groupe de travail sans lieu) Y - K - 1 (Aucune entreprise)
Donc, pour créer ma table, j'ai créé
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)
Je pense que cela permettrait de gérer toutes mes relations en plus de la nécessité d'une affectation d'avoir un emplacement s'il existe un groupe de travail (que je peux effectuer avec joie par programme ou avec des déclencheurs, je pense)
Cependant, lorsque je teste ce schéma, il me permet de saisir les informations suivantes ...
INSERT INTO test VALUES (1, null, null, null), (1, null, null, null);
... sans se plaindre. Je suppose que (1, null, null, null) ne s’égale pas car les valeurs null sont incluses. Si tel est le cas, y a-t-il moyen de gérer cette relation?
Toute aide serait appréciée!
La solution
Ceci est une fonctionnalité (bien que ce ne soit pas ce à quoi je m'attendais).
Ce fil suggère de faire de votre clé une clé primaire pour obtenir le comportement attendu:
Ceci est une fonctionnalité - une valeur NULL est un valeur indéfinie, donc deux NULL les valeurs ne sont pas les mêmes. Peut être un peu déroutant mais fait sens quand vous en pensez.
Un index UNIQUE garantit que les valeurs non NULL sont uniques; vous pourriez spécifier que votre colonne n'accepte pas Valeurs NULL.
Autres conseils
La seule façon pour moi de gérer cela sans déclencheurs / programmation supplémentaires serait d’avoir un seul " Aucune des réponses ci-dessus " valeur dans chacune des tables référencées, de sorte que votre test ressemble à
INSERT INTO test VALUES (1, NO_LOCATION, NO_WORKGROUP, NO_PROGRAM),
(1, NO_LOCATION, NO_WORKGROUP, NO_PROGRAM)
Où les identificateurs NO _ *
correspondent au type / longueur approprié pour vos colonnes ID. Cela échouerait alors, comme vous vous en doutez.
Dans MySQL NULL! = NULL, ou quoi que ce soit. Donc, c’est ce que l’UNIQUE ne fonctionne pas. Vous devez utiliser une autre valeur par défaut pour les blancs, comme zéro
Je pense qu'il est important de noter qu'il existe un moyen approprié pour que les valeurs NULL soient interprétées et gérées, et que le comportement présenté par l'OP correspond exactement à ce qu'il était destiné. Vous pouvez ignorer ce comportement et traiter votre requête comme bon vous semble sans objection de ma part, mais il serait peut-être bon de "accepter". une réponse qui décrit une forme de meilleure pratique plutôt qu'une préférence personnelle non standard.
Ou si vous n'êtes pas d'accord avec la meilleure pratique consensuelle, vous ne pouvez accepter aucune réponse.
Ce n’est pas une course à faire accepter une réponse le plus rapidement possible. La réflexion et la collaboration sont également censées faire partie du processus, je pense.