Ściśle mówiąc, unikatowa kolumna dopuszczająca wartość null (lub zestaw kolumn) może mieć wartość NULL (lub rekord wartości NULL) tylko raz, ponieważ posiadanie tej samej wartości (i obejmuje to NULL) więcej niż raz w oczywisty sposób narusza ograniczenie unikalności.
Nie oznacza to jednak, że koncepcja „unikatowych kolumn dopuszczających wartość null” jest prawidłowa; aby faktycznie zaimplementować go w dowolnej relacyjnej bazie danych, musimy tylko pamiętać, że tego rodzaju bazy danych mają być znormalizowane, aby poprawnie działać, a normalizacja zwykle obejmuje dodanie kilku (nie-encji) dodatkowych tabel w celu ustalenia relacji między jednostkami .
Spójrzmy na podstawowy przykład, biorąc pod uwagę tylko jedną „unikalną kolumnę dopuszczającą wartość null”, łatwo jest ją rozszerzyć na więcej takich kolumn.
Załóżmy, że mamy informacje reprezentowane przez taką tabelę:
create table the_entity_incorrect
(
id integer,
uniqnull integer null, /* we want this to be "unique and nullable" */
primary key (id)
);
Możemy to zrobić, oddzielając wartość uniqnull i dodając drugą tabelę, aby ustanowić relację między wartościami unikatowymi i the_entity (zamiast mieć unikalną wartość „wewnątrz” elementu 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)
);
Aby skojarzyć wartość uniqnull z wierszem w the_entity, musimy również dodać wiersz w the_relation.
Dla wierszy w the_entity, w których nie są skojarzone żadne unikalne wartości puste (tj. Dla tych, które umieścilibyśmy NULL w the_entity_incorrect), po prostu nie dodajemy wiersza w the_relation.
Zauważ, że wartości dla uniqnull będą unikalne dla całego the_relation, a także zauważ, że dla każdej wartości w the_entity może być co najwyżej jedna wartość w the_relation, ponieważ wymuszają to klucze podstawowy i obcy.
Następnie, jeśli wartość 5 dla unikqnull ma być skojarzona z identyfikatorem the_entity równym 3, musimy:
start transaction;
insert into the_entity (id) values (3);
insert into the_relation (the_entity_id, uniqnull) values (3, 5);
commit;
A jeśli wartość id równa 10 dla the_entity nie ma unikalnego odpowiednika, robimy tylko:
start transaction;
insert into the_entity (id) values (10);
commit;
Aby zdenormalizować te informacje i uzyskać dane, które mogłaby zawierać tabela taka jak the_entity_incorrect, musimy:
select
id, uniqnull
from
the_entity left outer join the_relation
on
the_entity.id = the_relation.the_entity_id
;
Operator „left external join” zapewnia, że w wyniku pojawią się wszystkie wiersze z the_entity, umieszczając NULL w unikatowej kolumnie, gdy w the_relation nie ma pasujących kolumn.
Pamiętaj, że każdy wysiłek poświęcony przez kilka dni (lub tygodni lub miesięcy) na zaprojektowanie dobrze znormalizowanej bazy danych (i odpowiednich denormalizujących poglądów i procedur) pozwoli Ci zaoszczędzić lata (lub dekady) bólu i zmarnowanych zasobów.