Mysql
 sql >> Database >  >> RDS >> Mysql

Struttura/progettazione del database

Non esiste una regola generale o Best Practice le chiavi esterne non dovrebbero essere annullabili. Molte volte ha perfettamente senso che un'entità non abbia una relazione con un'altra entità. Ad esempio, potresti avere una tabella di artisti che segui ma, al momento, non hai CD registrati da quegli artisti.

Per quanto riguarda i Media (CD, DVD, BluRay) che possono essere musica/audio o software, si può avere una tabella con le informazioni in comune e poi due chiavi esterne, una per ciascuna tabella di estensione (AudioData e SoftwareData), ma una deve essere NULL . Questo presenta una situazione chiamata, tra l'altro, arco esclusivo. Questo è generalmente considerato... problematico.

Pensa a una superclasse e due classi derivate in un linguaggio OO come Java o C++. Un modo per rappresentarlo in uno schema relazionale è:

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 )
);

Ora, se stai cercando un film, cerchi nella tabella AVData, quindi unisciti alla tabella Media per il resto delle informazioni e così via con software o giochi. Se hai un valore ID ma non sai di che tipo si tratta, cerca nella tabella Media e il valore Tipo ti dirà con quale delle tre (o più) tabelle di dati unirti. Il punto è che l'FK si riferisce a a la tabella generica, non da essa.

Ovviamente, un film, un gioco o un software può essere rilasciato su più di un tipo di supporto, quindi puoi avere tabelle di intersezione tra i Media tabella e le rispettive tabelle dati. Otoh, quelli sono generalmente etichettati con SKU diversi, quindi potresti volerli trattare anche come articoli diversi.

Il codice, come ci si potrebbe aspettare, può diventare abbastanza complicato, anche se non troppo male. Otoh, il nostro obiettivo di progettazione non è la semplicità del codice ma l'integrità dei dati. Ciò rende impossibile combinare, ad esempio, i dati di gioco con un elemento del film. E ti sbarazzi di avere un insieme di campi in cui solo uno deve avere un valore e gli altri devono essere nulli.