Er is geen algemene regel of best practice, de externe sleutels mogen niet nullbaar zijn. Vaak is het volkomen logisch dat een entiteit geen relatie heeft met een andere entiteit. U kunt bijvoorbeeld een tabel hebben met artiesten die u volgt, maar op dit moment heeft u geen cd's die zijn opgenomen door die artiesten.
Wat betreft het hebben van media (cd, dvd, BluRay) die muziek/audio of software kan zijn, kunt u een tabel hebben met de gemeenschappelijke informatie en vervolgens twee externe sleutels, één voor elke uitbreidingstabel (AudioData en SoftwareData), maar één moet NULL
zijn . Dit presenteert een situatie die onder andere een exclusieve boog wordt genoemd. Dit wordt over het algemeen als... problematisch beschouwd.
Denk aan een superklasse en twee afgeleide klassen in een OO-taal zoals Java of C++. Een manier om dat in een relationeel schema weer te geven is:
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 )
);
Als u nu op zoek bent naar een film, doorzoekt u de AVData-tabel, voegt u zich bij de Media-tabel voor de rest van de informatie enzovoort met software of games. Als je een ID-waarde hebt, maar niet weet wat voor soort het is, zoek dan in de Media-tabel en de Type-waarde zal je vertellen aan welke van de drie (of meer) gegevenstabellen je moet deelnemen. Het punt is dat de FK verwijst naar de generieke tabel, niet daaruit.
Natuurlijk kan een film of game of software op meer dan één mediatype worden uitgebracht, dus je kunt intersectietabellen hebben tussen de Media
tabel en de respectievelijke gegevenstabellen. Otoh, die zijn over het algemeen gelabeld met verschillende SKU's, dus misschien wil je ze ook als verschillende items behandelen.
De code kan, zoals je zou verwachten, behoorlijk ingewikkeld worden, maar niet al te slecht. Otoh, ons ontwerpdoel is niet de eenvoud van de code, maar de integriteit van gegevens. Hierdoor is het onmogelijk om bijvoorbeeld gamedata te mixen met een filmitem. En u hoeft geen reeks velden meer te hebben waarvan er slechts één een waarde moet hebben en de andere nul.