Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Estrutura/Design do Banco de Dados


Não há regra geral ou Melhor Prática de que as chaves estrangeiras não devem ser anuláveis. Muitas vezes faz todo o sentido que uma entidade não tenha um relacionamento com outra entidade. Por exemplo, você pode ter uma tabela de artistas que acompanha, mas, no momento, não possui CDs gravados por esses artistas.

Quanto a ter Mídia (CD, DVD, BluRay) que pode ser música/áudio ou software, você pode ter uma tabela com as informações em comum e depois duas chaves estrangeiras, uma para cada tabela de extensão (AudioData e SoftwareData), mas uma deve ser NULL . Isso apresenta uma situação chamada, entre outras coisas, de arco exclusivo. Isso é geralmente considerado... problemático.

Pense em uma superclasse e duas classes derivadas em uma linguagem OO como Java ou C++. Uma maneira de representar isso em um esquema relacional é:
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 )
);

Agora, se você estiver procurando por um filme, pesquise na tabela AVData, depois junte-se à tabela Media para o restante das informações e assim por diante com software ou jogos. Se você tiver um valor de ID, mas não souber de que tipo ele é, pesquise na tabela de mídia e o valor de tipo informará qual das três (ou mais) tabelas de dados para unir. O ponto é que o FK está se referindo a a tabela genérica, não a partir dela.

Claro, um filme ou jogo ou software pode ser lançado em mais de um tipo de mídia, então você pode ter tabelas de interseção entre a Media tabela e as respectivas tabelas de dados. Otoh, eles geralmente são rotulados com SKUs diferentes, então você também pode tratá-los como itens diferentes.

O código, como você pode esperar, pode ficar bastante complicado, embora não tão ruim. Otoh, nosso objetivo de design não é a simplicidade do código, mas a integridade dos dados. Isso torna impossível misturar, por exemplo, dados do jogo com um item de filme. E você se livra de ter um conjunto de campos onde apenas um deve ter um valor e os outros devem ser nulos.