web-dev-qa-db-fra.com

Touche étrangère NULL VS Clé étrangère à une chaîne vide

Ceci est une table pour un catalogue de médicaments. Certains ont une marque pharmaceutique, d'autres sont génériques (c'est-à-dire qu'ils n'auront jamais d'informations de marque)

CREATE TABLE medicine (
   id serial PRIMARY KEY,
   name text NOT NULL,
   brand_id integer
   CONSTRAINT brand_fk FOREIGN KEY (brand_id) REFERENCES brand (id)       
);

CREATE TABLE brand (
  id serial PRIMARY KEY,
  name text NOT NULL
);

Pour stocker des médicaments génériques, par exemple abc & xyz, il y a 2 options:

  1. Utilisez null pour la clé étrangère brand_id

    INSERT INTO medicine (name, brand_id) VALUES ('abc', NULL)
    INSERT INTO medicine (name, brand_id) VALUES ('xyz', NULL)

  2. Insérer juste 1 chaîne vide en nom de marque et utilisez-le pour tous les médicaments génériques de la marque_ID

    INSERT INTO brand (id, name) VALUES (1, '')
    INSERT INTO medicine (name, brand_id) VALUES ('abc', 1)
    INSERT INTO medicine (name, brand_id) VALUES ('xyz', 1)

D'après ce que j'ai lu sur Stackexchange, il semble que 1 Est la manière générale de le faire. Toutefois, si je veux un index unique sur la médecine Nom & Brand_id, je devrai utiliser index partiels (i.e. 2 index des index respectivement où brand_id IS NULL & brand_id is NOT NULL).

Si je passe avec la deuxième approche, je peux y parvenir avec un seul index.

Existe-t-il d'autres avantages/inconvénients de l'une de ces approches. Je pense que la deuxième méthode n'est pas conventionnelle et il pourrait y avoir des problèmes que je vais découvrir plus tard en cours de route.

PS J'ai utilisé l'exemple de médicaments pour illustrer ma requête, mais je veux comprendre les mérites techniques de la solution purement du point de vue de la base de données, c'est-à-dire sans aller dans une discussion sur laquelle une approche serait meilleure pour l'exemple de la médecine.

4
user4150760

La réponse réside dans l'ambiguïté de votre question:

Cependant, si je veux un index unique sur la médecine name & brand_id ...

Vous ne voulez pas vraiment "un index unique". Vous voulez appliquer certaines règles. Un index unique est un signifie à une fin; A Outil. La question est la suivante: qu'est-ce que vous voulez?

Voulez-vous qu'il ne puisse être qu'une seule instance d'un name avec une marque inconnue? Ou peut-il y avoir plusieurs instances? Cela dépend de ce que "inconnu" ou "manquant" ou "vide" ou NULL est censé signifier pour vous.

Le sens canonique de NULL est "inconnu". Nous ne savons simplement pas, ce qui va ici, cela pourrait être n'importe quoi, y compris rien (vide (vide ('') dans les types de chaîne, 0 en types numériques).

Si vous voulez autoriser une marque générique, incluez une entrée dans brand, appelez-le "générique" ou " [~ # ~ # ~ # ~ ] "ou autre chose. J'aime utiliser la valeur d'identification 0 Pour une telle entrée.

Ensuite, votre indice ou votre contrainte unique fait ce qu'il est censé faire: autoriser une seule instance de (brand_id, name) Dans la table medicine. Mais plusieurs entrées avec (brand_id, NULL) sont toujours possibles. Régler brand_id NOT NULL Si vous ne le voulez pas.

La meilleure solution dépend également des requêtes typiques et des détails de votre configuration. Assurez-vous de Document exactement Ce que NULL/vide/0 est censé signifier et pourquoi vous avez choisi de le concevoir comme ça. Cela peut sembler cristal clair au moment où vous le mettez en œuvre, mais peut être déroutant plus tard.

J'ai ajouté un autre lien vers la réponse que vous avez référencée:

6
Erwin Brandstetter