Няма общо правило или най-добра практика външните ключове да не могат да бъдат нулирани. Много пъти е напълно логично субектът да няма връзка с друг обект. Например, може да имате таблица с изпълнители, които проследявате, но в момента нямате компактдискове, записани от тези изпълнители.
Що се отнася до наличието на носител (CD, DVD, BluRay), който може да бъде музика/аудио или софтуер, можете да имате таблица с обща информация и след това два външни ключа, по един към всяка таблица с разширения (AudioData и SoftwareData), но един трябва да е NULL
. Това представлява ситуация, наречена, наред с други неща, изключителна дъга. Това обикновено се счита за...проблематичен.
Помислете за суперклас и два извлечени класа на OO език като Java или C++. Един от начините да представите това в релационна схема е:
create table Media(
ID int not null, -- identity, auto_generated, generated always as identity...
Type char( 1 ) not null,
Format char( 1 ) not null,
... <other common data>,
constraint PK_Media primary key( ID ),
constraint FK_Media_Type foreign key( Type )
references MediaTypes( ID ), -- A-A/V, S-Software, G-Game
constraint FK_Media_Format foreign key( Format )
references MediaFormats( ID ) -- C-CD, D-DVD, B-BluRay, etc.
);
create unique index UQ_Media_ID_Type( ID, Type ) on Media;
create table AVData( -- For music and video
ID int not null,
Type char( 1 ) not null,
... <audio-only data>,
constraint PK_AVData primary key( ID ),
constraint CK_AVData_Type check( Type = 'A',
constraint FK_AVData_Media foreign key( ID, Type )
references Media( ID, Type )
);
create table SWData( -- For software, data
ID int not null,
Type char( 1 ) not null,
... <software-only data>,
constraint PK_SWData primary key( ID ),
constraint CK_SWData_Type check( Type = 'S',
constraint FK_SWData_Media foreign key( ID, Type )
references Media( ID, Type )
);
create table GameData( -- For games
ID int not null,
Type char( 1 ) not null,
... <game-only data>,
constraint PK_GameData primary key( ID ),
constraint CK_GameData_Type check( Type = 'G',
constraint FK_GameData_Media foreign key( ID, Type )
references Media( ID, Type )
);
Сега, ако търсите филм, търсите в таблицата AVData, след това се присъединявате към таблицата Media за останалата информация и така нататък със софтуер или игри. Ако имате стойност на идентификатор, но не знаете какъв вид е, потърсете в таблицата Media и стойността Type ще ви каже с коя от трите (или повече) таблици с данни да се присъедините. Въпросът е, че FK се позовава на за общата таблица, а не от нея.
Разбира се, филм, игра или софтуер могат да бъдат пуснати на повече от един тип медия, така че можете да имате пресечни таблици между Media
таблица и съответните таблици с данни. О, те обикновено са етикетирани с различни SKU, така че може да искате да ги третирате като различни артикули.
Кодът, както може да очаквате, може да стане доста сложен, макар и не толкова лош. Ото, нашата цел на дизайна не е простотата на кода, а целостта на данните. Това прави невъзможно смесването, например, на данни от играта с филмов елемент. И вие се отървавате от набор от полета, където само едно трябва да има стойност, а останалите да са нулеви.