Mauvaise pratique Nullable Foreign Key?

114

Supposons que vous ayez une table Commandes avec une clé étrangère vers un ID client. Maintenant, supposons que vous souhaitiez ajouter une commande sans numéro de client (si cela devrait être possible est une autre question), vous devrez rendre la clé étrangère NULL ... Est-ce une mauvaise pratique ou préférez-vous travailler avec une table de liens entre Commandes et clients? Bien que la relation soit de 1 à n, une table de liens le ferait de n à n. Par contre, avec une table de liens, je n'ai plus ces NULLS ...

Il n'y aura en fait pas beaucoup de NULL dans la base de données, car un enregistrement avec une clé étrangère à NULL est juste temporairement jusqu'à ce qu'un client pour la commande soit ajouté.

(Dans mon cas, ce n'est pas une commande et un client).

EDIT: Qu'en est-il d'un client non affecté vers lequel établir un lien?

Lieven Cardoen
la source
9
C'est l'un des principaux objectifs de la disponibilité de NULL dans un schéma de base de données. De plus, c'est pourquoi vous pouvez déclarer des champs NULL ou NOT NULL, afin que les exigences spécifiques de votre schéma puissent être satisfaites.
gahooa
7
J'ai d'abord lu la question en tant que clés primaires nulles , et j'étais sur le point de me lancer avec quelques conseils forts ... :-)
Andrzej Doyle

Réponses:

51

Avoir la table des liens est probablement une meilleure option. Au moins, il ne viole pas la normalisation BCNF (Boyce-Codd forme normale). cependant je préférerais être pragmatique. Si vous avez très peu de ces valeurs nulles et qu'elles ne sont que temporaires, je pense que vous devriez ignorer la table des liens car elle ne fait qu'ajouter de la complexité au schéma.

Sur une note latérale; l'utilisation d'une table de liens ne rend pas nécessairement n à n, si vous dans la table de liens utilisez la clé étrangère qui pointe vers votre table de commandes comme clé primaire dans cette table de liens, la relation est toujours 1..n. Il ne peut y avoir qu'une seule entrée dans cette table de liens par commande.

Patrik Hägne
la source
2
source__destination_link ou SourceDestination
Svisstack
7
Je serais intéressé à entendre parler d'une situation où il est préférable d'avoir une table de liens, je n'ai jamais rencontré une situation où cela aurait amélioré le flux de processus de quelque manière que ce soit.
Reimius
5
Comme indiqué dans ma réponse, je serais pragmatique dans ce cas précis et n'utiliserais pas de table de liens. Je suis sûr que les formes normales n'ont pas été inventées pour améliorer le flux de processus, mais plutôt pour assurer la cohérence et éviter la redondance. C'est une discussion très générale cependant, je pense qu'elle doit être considérée au cas par cas.
Patrik Hägne
110

Non Il n'y a rien de mal avec les FK Nullable. Ceci est courant lorsque l'entité vers laquelle pointe le FK est dans une relation (zéro ou un) à (1 ou plusieurs) avec la table référencée par clé primaire.

Un exemple pourrait être si vous aviez à la fois une adresse physique et un attribut (colonne) d'adresse postale dans une table, avec des FK vers une table d'adresses. Vous pouvez rendre l'adresse physique NULL à gérer lorsque l'entité n'a qu'une boîte postale (adresse postale) et l'adresse postale Nullable à gérer lorsque l'adresse postale est la même que l'adresse physique (ou non).

Charles Bretana
la source
39

Les colonnes Nullable peuvent être dans 1NF à 5NF, mais pas dans 6NF selon ce que j'ai lu.

Seulement si vous savez mieux que Chris Date "ce que signifie vraiment la première forme normale". Si x et y sont tous les deux nullables, et en effet dans certaines lignes x et y sont tous les deux null, alors WHERE x=yne donne pas true. Cela prouve au-delà de tout doute raisonnable que null n'est pas une valeur (car toute valeur réelle est toujours égale à elle-même). Et puisque le RM prescrit qu '"il doit y avoir une valeur dans chaque cellule d'une table", toute chose qui contient éventuellement des valeurs nulles n'est pas une chose relationnelle, et donc la question de 1NF ne se pose même pas.

J'ai entendu dire que les colonnes Nullable cassent en général le premier degré de normalisation.

Voir ci-dessus pour la bonne raison qui sous-tend cet argument.

Mais en pratique, c'est très pratique.

Seulement si vous êtes immunisé contre les maux de tête que cela provoque habituellement dans le reste du monde. Un de ces maux de tête (et ce n'est que mineur, comparativement à d'autres nullphénomènes) est le fait que WHERE x=ydans SQL signifie en fait WHERE x is not null and y is not null and x=y, mais que la plupart des programmeurs ne sont tout simplement pas conscients de ce fait et ne font que le lire. Parfois sans aucun mal, d'autres fois non.

En fait, les colonnes Nullable enfreignent l'une des règles de conception de base de données les plus fondamentales: ne combinez pas des éléments d'information distincts dans une colonne. Les valeurs nulles font exactement cela parce qu'elles combinent la valeur booléenne «ce champ est / n'est pas vraiment présent» avec la valeur réelle.

Erwin Smout
la source
18
+1 pour "O x n'est pas nul et y n'est pas nul et x = y". Je n'en étais pas conscient.
RobM
1
Argument et exemples très bien présentés.
pedz
1
Un problème. Lorsque la valeur «n'existe pas» (ce qui est un scénario réel) et que l'attribut de base de données n'autorise pas les valeurs nulles, quelle que soit la valeur de l'attribut est FAUX. En ce qui concerne les maux de tête, rappelez-vous, KISS, cela ne signifie pas seulement garder les choses simples, cela signifie garder les choses aussi simples que possible, mais pas plus simples. Si le «modèle relationnel» exige un résultat irréaliste et stupide, alors peut-être que les règles doivent être élargies pour gérer les données nécessaires du monde réel?
Charles Bretana
1
Il a été démontré qu'une logique à trois valeurs conduit à un besoin de logique à quatre valeurs, ce qui conduit à un besoin de logique à cinq valeurs, etc. etc. La logique à deux valeurs est suffisante, mais les structures de données que nous obtenons lorsque l'appliquer rend "aussi simple que possible" encore beaucoup moins simple que "aussi simple que nous le voudrions".
Erwin Smout
2
Chris Date, Logic & Databases, Chpt 6, "Pourquoi la logique du SGBD relationnel ne doit pas avoir de nombreuses valeurs", p. 145. La liste des références à ce chapitre devrait également être intéressante, en particulier celles impliquant McGoveran.
Erwin Smout
13

Je ne vois rien de mal à cela, il s'agit simplement d'une relation n-1 facultative qui sera représentée par un null dans la clé étrangère. Sinon, si vous mettez votre table de liens, vous devrez gérer qu'elle ne devienne pas une relation nn, ce qui causera encore plus de problèmes.

pedromarce
la source
2
En fait, c'est une relation 0-N, pas une relation 1-N facultative. Mais je suis d'accord avec toi.
Eric J.
5
Gérer? C'est une simple contrainte UNIQUE du côté 0 vers 1!
wqw
2
Oui, c'est une contrainte UNIQUE, mais vous devrez également faire face à d'éventuelles exceptions plus tard dans votre code en raison de cette contrainte ...
pedromarce
4

Des relations optionnelles sont certainement possibles dans le modèle relationnel.

Vous pouvez utiliser des valeurs nulles pour exprimer l'absence de relation. Ils sont pratiques, mais ils vous causeront les mêmes maux de tête que les nulls vous causent ailleurs. Les jointures sont un endroit où elles ne causent aucun problème. Les lignes qui ont une valeur null dans la clé étrangère ne correspondent à aucune ligne de la table référencée. Alors ils abandonnent une jointure intérieure. Si vous faites des jointures externes, vous allez quand même avoir affaire à des valeurs nulles.

Si vous voulez vraiment éviter les valeurs nulles (6ème forme normale), vous pouvez décomposer la table. L'une des deux tables décomposées a deux colonnes de clé étrangère. L'un est la clé étrangère facultative que vous possédez et l'autre est une clé étrangère référençant la clé primaire de la table d'origine. Maintenant, vous devez utiliser des contraintes pour empêcher la relation de devenir plusieurs-à-plusieurs, si vous voulez éviter cela.

Walter Mitty
la source
2

L'utilisation de NULL serait un bon moyen de nettoyer les commandes incomplètes:

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

Ce qui précède afficherait les commandes de plus de 15 minutes sans identifiant client associé.

matpie
la source
1

Si vous n'ajoutez la commande que temporairement sans identifiant client jusqu'à ce qu'un client soit défini, ne serait-il pas plus simple d'ajouter le client et la commande en une seule transaction, supprimant ainsi le besoin de l'entrée de clé étrangère NULL et évitant toute contrainte ou déclencheur vous avez configuré une violation?

Normalement, cette situation se produit dans les applications Web où la commande est détaillée avant que le client ne définisse qui il / elle est. Et dans ces situations, la commande est conservée dans l'état du serveur ou dans un cookie jusqu'à ce que tout l'état nécessaire à une commande complète soit fourni, moment auquel la commande est conservée dans la base de données.

Les clés étrangères NULL conviennent pour des choses comme les adresses, comme mentionné ci-dessus. Mais un champ client NULL n'a pas de sens pour une commande et doit être contraint.

Mark Green
la source
La commande-client était un exemple. Dans mon application, cela ressemble plus à des adresses. Impossible de trouver immédiatement un exemple qui était tout à fait correct. THX.
Lieven Cardoen
1
Cela pourrait être un scénario valide si la base de données était utilisée pour stocker des articles dans un panier, où le panier n'appartient pas à un utilisateur enregistré.
Johnie Karr
1

Vous pouvez toujours ajouter une ligne artificielle à votre table Customer, quelque chose comme Id = -1 et CustomerName = 'Unknown', puis dans les cas où vous définiriez normalement votre CustomerId dans Order NULL, définissez-le sur -1.

Cela vous permet de ne pas avoir de FK nullable mais représente toujours le manque de données de manière appropriée (et vous évitera des utilisateurs en aval ne sachant pas comment gérer les NULL).

Stephen S.
la source
Juste pour ajouter à cela, rappelez-vous que NULLS n'est pas stocké dans un index (dans oracle), donc cela signifie que sauter la table de liens et opter pour le FK nullable aurait du sens - du point de vue des performances. L'autre chose dont cela pourrait dépendre est si vous voulez stocker autre chose dans cette table de liens, par exemple, QUI a fait le lien et quand? Le lien est-il maintenant inactif / supprimé (mais il l'était autrefois?)
Worthy7
C'est une mauvaise idée. Si vous avez une clé étrangère qui est définie et que les données sur lesquelles elle pointe sont supprimées ultérieurement, vous n'obtiendrez pas l'exception de clé étrangère et vos données sont désormais insensées. Pire encore, si quelque chose d'autre est attribué plus tard à cette clé, vous pointez entièrement vers le mauvais client
IcedDante
0

Les FK nulles pour les relations optionnelles plusieurs-à-un sont tout à fait correctes.

Henning
la source
-1

J'ai entendu dire que les colonnes Nullable en général cassent le premier degré de normalisation. Mais en pratique, c'est très pratique.

Bryan McLemore
la source
3
Les colonnes Nullable peuvent être dans 1NF à 5NF, mais pas dans 6NF selon ce que j'ai lu.
Walter Mitty
-1

Oui, il y a quelque chose qui ne va pas. Ce n'est pas une clé étrangère si elle est nullable. Sa conception de base de données par code. Peut-être que vous faites un lien zéro vers unassigned. ou "Unassigned" si vous utilisez un caractère col. Gardez l'intégrité de vos données à 100%.

danny117
la source