Une clé étrangère peut-elle être NULL et / ou dupliquée?

325

Veuillez clarifier deux choses pour moi:

  1. Une clé étrangère peut-elle être NULL?
  2. Une clé étrangère peut-elle être dupliquée?

Aussi juste que je sache, NULLne devrait pas être utilisé dans des clés étrangères, mais dans certaines de mes applications, je suis capable d'entrer NULLà la fois dans Oracle et SQL Server, et je ne sais pas pourquoi.

confitures
la source
1
@Adrian: À ma connaissance, la clé étrangère ne peut pas être nulle, mais elle prend null dans le serveur SQL et Oracle. pouvez-vous expliquer pourquoi?
jams
@Jams - lisez le lien dans ma réponse.
JNK
11
cela ne peut pas être supprimé car les réponses et la question sont utiles. N'hésitez pas à modifier la question pour l'améliorer.
Jeff Atwood
Veuillez diviser la question sur les doublons. Seul celui sur les NULL est répondu ci-dessous.
reinierpost

Réponses:

529

Réponse courte: Oui, il peut être NULL ou en double.

Je veux expliquer pourquoi une clé étrangère peut avoir besoin d'être nulle ou peut être unique ou non unique. Rappelez-vous d'abord qu'une clé étrangère nécessite simplement que la valeur de ce champ existe d'abord dans une autre table (la table parent). C'est tout ce qu'un FK est par définition. Nul par définition n'est pas une valeur. Null signifie que nous ne savons pas encore quelle est la valeur.

Permettez-moi de vous donner un exemple concret. Supposons que vous ayez une base de données qui stocke les propositions de vente. Supposons en outre que chaque proposition ne comporte qu'un seul commercial et un seul client. Ainsi, votre table de proposition aurait deux clés étrangères, une avec l'ID client et l'autre avec l'ID représentant commercial. Cependant, au moment de la création de l'enregistrement, un commercial n'est pas toujours affecté (car personne n'est encore libre de travailler dessus), l'ID client est donc renseigné mais l'ID commercial peut être nul. En d'autres termes, vous devez généralement avoir la possibilité d'avoir un FK nul lorsque vous ne connaissez pas sa valeur au moment où les données sont entrées, mais vous connaissez d'autres valeurs dans le tableau qui doivent être entrées. Pour autoriser les valeurs nulles dans un FK, tout ce que vous avez à faire est généralement d'autoriser les valeurs nulles sur le champ contenant le FK. La valeur nulle est distincte de l'idée qu'il s'agit d'un FK.

Qu'elle soit unique ou non unique, cela signifie que la table a une relation un-un ou un-plusieurs avec la table parent. Maintenant, si vous avez une relation un-à-un, il est possible que vous puissiez avoir les données dans une seule table, mais si la table devient trop large ou si les données sont sur un sujet différent (l'employé - exemple d'assurance @tbone a donné par exemple), alors vous voulez des tables séparées avec un FK. Vous voudrez alors faire de ce FK soit aussi le PK (qui garantit l'unicité) ou y mettre une contrainte unique.

La plupart des FK sont pour une relation un à plusieurs et c'est ce que vous obtenez d'un FK sans ajouter de contrainte supplémentaire sur le terrain. Vous avez donc une table de commande et la table des détails de la commande par exemple. Si le client commande dix articles à la fois, il a une commande et dix enregistrements de détail de commande qui contiennent le même ID de commande que le FK.

HLGEM
la source
13
Donc, c'est mieux que d'avoir un faux vendeur nommé "Unassigned"?
Thomas Weller
8
Un commentaire. Les valeurs nulles laissent beaucoup de place aux erreurs dans la requête par des personnes qui ne savent pas comment SQL (mis) gère 3VL. Si un vendeur n'est vraiment pas nécessaire pour une certaine table r, il suffit de ne pas inclure cet enregistrement. Une table distincte peut être «PropositionAssignéeTo» ou une autre, avec les contraintes appropriées. Un rédacteur de requêtes peut ensuite se joindre à cette table et fournir sa propre logique pour tout ce que nous voulons faire lorsqu'une proposition n'a pas de vendeur. NULL ne signifie pas seulement "nous ne savons pas" - il peut être utilisé pour beaucoup de choses (c'est pourquoi c'est presque toujours une mauvaise idée)
N West
26
@nWest, je n'autorise pas les personnes incompétentes à interroger mes bases de données et tout développeur qui ne sait pas comment gérer les valeurs nulles est incompétent. Il y a des moments où les données ne sont pas connues au moment de la saisie initiale des données pour un champ particulier mais les autres champs sont nécessaires à ce moment.
HLGEM
28
@ThomasWeller Référencer un faux vendeur ("Non affecté") aggrave le problème. Je suppose que votre table de vendeur comporte plusieurs colonnes ...? Quel numéro d'assurance sociale de M. Unassigned? À quel département est-il affecté? Qui est son patron? J'espère que vous comprenez bien: lorsque vous créez un vendeur "non affecté", vous découvrez rapidement que vous avez échangé NULLune table contre plusieurs NULLdans une autre.
Gili
1
@ThomasWeller Vous aurez également un problème si / quand vous devez localiser votre interface.
tobiv
45

De la bouche du cheval:

Les clés étrangères autorisent des valeurs de clé toutes NULL, même s'il n'y a pas de clés PRIMARY ou UNIQUE correspondantes

Aucune contrainte sur la clé étrangère

Lorsqu'aucune autre contrainte n'est définie sur la clé étrangère, n'importe quel nombre de lignes de la table enfant peut référencer la même valeur de clé parent. Ce modèle autorise les null dans la clé étrangère. ...

Contrainte NOT NULL sur la clé étrangère

Lorsque les valeurs NULL ne sont pas autorisées dans une clé étrangère, chaque ligne de la table enfant doit référencer explicitement une valeur dans la clé parent car les valeurs NULL ne sont pas autorisées dans la clé étrangère.

N'importe quel nombre de lignes de la table enfant peut référencer la même valeur de clé parent, ce modèle établit donc une relation un-à-plusieurs entre le parent et les clés étrangères. Cependant, chaque ligne de la table enfant doit avoir une référence à une valeur de clé parent; l'absence d'une valeur (null) dans la clé étrangère n'est pas autorisée. Le même exemple dans la section précédente peut être utilisé pour illustrer une telle relation. Cependant, dans ce cas, les employés doivent avoir une référence à un service spécifique.

Contrainte UNIQUE sur la clé étrangère

Lorsqu'une contrainte UNIQUE est définie sur la clé étrangère, une seule ligne de la table enfant peut référencer une valeur de clé parent donnée. Ce modèle autorise les null dans la clé étrangère.

Ce modèle établit une relation un à un entre le parent et les clés étrangères qui autorise des valeurs indéterminées (null) dans la clé étrangère. Par exemple, supposons que la table des employés contienne une colonne nommée MEMBERNO, faisant référence à un numéro de membre de l'employé dans le régime d'assurance de l'entreprise. De plus, une table nommée INSURANCE a une clé primaire nommée MEMBERNO et les autres colonnes de la table conservent les informations respectives relatives à une police d'assurance des employés. Le MEMBERNO dans la table des employés doit être à la fois une clé étrangère et une clé unique:

  • Pour appliquer des règles d'intégrité référentielle entre les tables EMP_TAB et INSURANCE (la contrainte FOREIGN KEY)

  • Pour garantir que chaque employé dispose d'un numéro de membre unique (la contrainte de clé UNIQUE)

Contraintes UNIQUES et NON NULES sur la clé étrangère

Lorsque les contraintes UNIQUE et NOT NULL sont définies sur la clé étrangère, une seule ligne de la table enfant peut référencer une valeur de clé parent donnée, et comme les valeurs NULL ne sont pas autorisées dans la clé étrangère, chaque ligne de la table enfant doit explicitement faire référence une valeur dans la clé parent.

Regarde ça:

Lien Oracle 11g

tbone
la source
16

Oui, la clé étrangère peut être nulle comme indiqué ci-dessus par les programmeurs seniors ... J'ajouterais un autre scénario où la clé étrangère devra être nulle .... supposons que nous ayons des tableaux de commentaires, des images et des vidéos dans une application qui permet des commentaires sur les images et vidéos. Dans le tableau des commentaires, nous pouvons avoir deux images de clés étrangères PicturesId et VideosId avec la clé principale CommentId. Ainsi, lorsque vous commentez une vidéo, seul VideosId est requis et pictureId est nul ... et si vous commentez une image, PictureId uniquement est requis et VideosId est nul ...

Touseef Ahmed Awan
la source
1
Je pense qu'il existe une meilleure façon de résoudre ce problème. Plutôt que de créer de nouvelles colonnes, vous pouvez avoir deux colonnes, à savoir "id" et "type", qui contiendront l'id et le nom de la table de clés étrangères. Par exemple, id = 1, type = Picture représentera le lien vers la table Picture avec l'id 1. L'avantage d'utiliser cette solution est que vous n'aurez pas à créer de nouvelles colonnes lorsque des commentaires sont ajoutés à des tables supplémentaires. L'inconvénient ne sera pas une contrainte de clé étrangère au niveau db, mais la contrainte devra être au niveau de l'application.
Agent47DarkSoul
4
@Agent: Nous avons eu cette "solution" dans l'utilisation de la production. Ne le fais pas, c'est terrible. Faire des requêtes devient ce gâchis de "si c'est de type 1, joignez-vous à cette table, sinon joignez-vous à cela". Ce fut un cauchemar pour nous. Nous avons fini par faire ce que dit cette réponse et avons créé une nouvelle colonne pour chaque type de jointure. La création de colonnes est bon marché. À peu près, ce n'est qu'un défaut, c'est que beaucoup de colonnes rendent Toad difficile à utiliser, mais ce n'est qu'un défaut de Toad.
user128216
1
@FighterJet Rails fournit un excellent cadre ORM qui gère même les requêtes complexes avec cette solution.
Agent47DarkSoul
2
@Agent: Peut-être que c'est possible ... mais si vous pouvez le rendre simple, pourquoi le rendre complexe? Et peut-être que "cauchemar" n'était pas le bon mot à utiliser: c'était juste très gênant. Nous n'avons pas (beaucoup) souffert de problèmes d'intégrité des données.
user128216
7

cela dépend du rôle que cela foreign keyjoue dans votre relation.

  1. si foreign keyc'est aussi un key attributedans votre relation, alors ça ne peut pas être NULL
  2. s'il foreign keys'agit d'un attribut normal dans votre relation, il peut être NULL.
shinxg
la source
3

Voici un exemple utilisant la syntaxe Oracle: Créons d'
abord une table COUNTRY

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

Créer la table 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 ) ;

Cela fonctionne parfaitement bien dans Oracle. Notez que la clé étrangère COUNTRY_ID dans la deuxième table n'a pas "NOT NULL".

Maintenant, pour insérer une ligne dans la table PROVINCE, il suffit de spécifier uniquement PROVINCE_ID. Toutefois, si vous avez également choisi de spécifier un COUNTRY_ID, il doit déjà exister dans la table COUNTRY.

Mouhcine
la source
1

Par défaut, il n'y a pas de contraintes sur la clé étrangère, la clé étrangère peut être nulle et dupliquée.

lors de la création d'une table / modification de la table, si vous ajoutez une contrainte d'unicité ou non nulle, alors seulement elle n'autorisera pas les valeurs nulles / dupliquées.

nitin lalwani
la source
0

Autrement dit, les relations «non identifiantes» entre entités font partie du modèle ER et sont disponibles dans Microsoft Visio lors de la conception du diagramme ER. Cela est nécessaire pour appliquer la cardinalité entre les entités de type "zéro ou plus de zéro" ou "zéro ou un". Notez ce "zéro" dans la cardinalité au lieu de "un" dans "un à plusieurs".

Maintenant, un exemple de relation non identificatrice où la cardinalité peut être "zéro" (non identifiant) est quand nous disons qu'un enregistrement / objet dans une entité-A "peut" ou "peut ne pas" avoir une valeur comme référence à l'enregistrement / s dans une autre entité-B.

Comme il existe une possibilité pour un enregistrement de l'entité-A de s'identifier aux enregistrements de l'autre entité-B, il devrait donc y avoir une colonne dans l'entité-B pour avoir la valeur d'identité de l'enregistrement de l'entité-B. Cette colonne peut être "Null" si aucun enregistrement dans l'entité-A n'identifie les enregistrements (ou les objets) dans l'entité-B.

Dans le paradigme orienté objet (monde réel), il existe des situations où un objet de classe B ne dépend pas nécessairement (fortement couplé) de l'objet de classe A pour son existence, ce qui signifie que la classe B est vaguement couplée à la classe. Un tel que la classe A peut "contenir" (confinement) un objet de la classe A, par opposition au concept d'objet de la classe B doit avoir (composition) un objet de la classe A, pour son (objet de la classe) B) création.

Du point de vue de la requête SQL, vous pouvez interroger tous les enregistrements de l'entité-B qui sont "non nuls" pour la clé étrangère réservée à l'entité-B. Cela apportera tous les enregistrements ayant une certaine valeur correspondante pour les lignes dans l'entité-A, sinon tous les enregistrements avec une valeur nulle seront les enregistrements qui n'ont aucun enregistrement dans l'entité-A dans l'entité-B.

Fakhar
la source
-1

Je pense qu'il vaut mieux considérer la cardinalité possible que nous avons dans les tableaux. Nous pouvons avoir une cardinalité minimale possible nulle. Lorsqu'il est facultatif, la participation minimale des tuples de la table associée peut être nulle. Vous devez maintenant faire en sorte que les valeurs de clé étrangère soient autorisées à être nulles.

Mais la réponse est que tout dépend de l'entreprise.

user9274383
la source
-3

L'idée d'une clé étrangère est basée sur le concept de référencer une valeur qui existe déjà dans la table principale. C'est pourquoi il est appelé une clé étrangère dans l'autre table. Ce concept est appelé intégrité référentielle. Si une clé étrangère est déclarée comme un champ nul, elle violera la logique même de l'intégrité référentielle. À quoi fera-t-il référence? Il ne peut faire référence qu'à quelque chose qui est présent dans le tableau principal. Par conséquent, je pense qu'il serait faux de déclarer un champ de clé étrangère nul.

SQLDev
la source
Il ne peut référencer «rien» ou vous ne connaissez pas encore sa valeur NULL, mais ce que l'intégrité référentielle dit, c'est que s'il fait référence à «quelque chose», il doit être là.
yaxe
-7

Je pense que la clé étrangère d'une table est également la clé primaire d'une autre table.Ainsi, elle n'autorise pas les valeurs nulles.

user4532553
la source