À proprement parler, une colonne NULL unique (ou un ensemble de colonnes) ne peut être NULL (ou un enregistrement de NULL) qu'une seule fois, car avoir la même valeur (et cela inclut NULL) plus d'une fois enfreint évidemment la contrainte d'unicité.
Cependant, cela ne signifie pas que le concept de "colonnes Nullables uniques" est valide; pour l'implémenter dans n'importe quelle base de données relationnelle, nous devons juste garder à l'esprit que ce type de bases de données est censé être normalisé pour fonctionner correctement, et la normalisation implique généralement l'ajout de plusieurs tables supplémentaires (non-entité) pour établir des relations entre les entités .
Prenons un exemple de base en considérant une seule "colonne Nullable unique", il est facile de l'étendre à plusieurs colonnes de ce type.
Supposons que nous les informations représentées par un tableau comme celui-ci:
create table the_entity_incorrect
(
id integer,
uniqnull integer null, /* we want this to be "unique and nullable" */
primary key (id)
);
Nous pouvons le faire en mettant uniqnull à part et en ajoutant une deuxième table pour établir une relation entre les valeurs uniqnull et the_entity (plutôt que d'avoir uniqnull "inside" the_entity):
create table the_entity
(
id integer,
primary key(id)
);
create table the_relation
(
the_entity_id integer not null,
uniqnull integer not null,
unique(the_entity_id),
unique(uniqnull),
/* primary key can be both or either of the_entity_id or uniqnull */
primary key (the_entity_id, uniqnull),
foreign key (the_entity_id) references the_entity(id)
);
Pour associer une valeur de uniqnull à une ligne dans the_entity, nous devons également ajouter une ligne dans the_relation.
Pour les lignes de the_entity où aucune valeur uniqnull n'est associée (c'est-à-dire pour celles que nous placerions NULL dans the_entity_incorrect), nous n'ajoutons simplement pas de ligne dans the_relation.
Notez que les valeurs pour uniqnull seront uniques pour toute la_relation, et notez également que pour chaque valeur de l'entité, il peut y avoir au plus une valeur dans la_relation, puisque les clés primaires et étrangères sur celle-ci imposent cela.
Ensuite, si une valeur de 5 pour uniqnull doit être associée à un id the_entity de 3, nous devons:
start transaction;
insert into the_entity (id) values (3);
insert into the_relation (the_entity_id, uniqnull) values (3, 5);
commit;
Et, si une valeur id de 10 pour the_entity n'a pas d'équivalent unique, nous faisons seulement:
start transaction;
insert into the_entity (id) values (10);
commit;
Pour dénormaliser ces informations et obtenir les données qu'une table comme the_entity_incorrect contiendrait, nous devons:
select
id, uniqnull
from
the_entity left outer join the_relation
on
the_entity.id = the_relation.the_entity_id
;
L'opérateur "jointure externe gauche" garantit que toutes les lignes de l'entité apparaîtront dans le résultat, en plaçant NULL dans la colonne uniqnull lorsqu'aucune colonne correspondante n'est présente dans the_relation.
N'oubliez pas que tout effort passé pendant quelques jours (ou semaines ou mois) à concevoir une base de données bien normalisée (et les vues et procédures de dénormalisation correspondantes) vous fera économiser des années (ou des décennies) de douleur et de gaspillage de ressources.