sql >> Base de Datos >  >> RDS >> Mysql

Estructura/diseño de la base de datos

No existe una regla general o una práctica recomendada de que las claves foráneas no deban ser anulables. Muchas veces tiene mucho sentido que una entidad no tenga una relación con otra entidad. Por ejemplo, puede tener una tabla de artistas a los que sigue pero, por el momento, no tiene ningún CD grabado por esos artistas.

En cuanto a tener Medios (CD, DVD, BluRay) que pueden ser música/audio o software, puede tener una tabla con la información en común y luego dos claves foráneas, una para cada tabla de extensión (AudioData y SoftwareData), pero una debe ser NULL . Esto presenta una situación denominada, entre otras cosas, arco exclusivo. Esto generalmente se considera que es... problemático.

Piense en una superclase y dos clases derivadas en un lenguaje OO como Java o C++. Una forma de representar eso en un esquema relacional es:

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

Ahora, si está buscando una película, busque en la tabla AVData, luego únase a la tabla Media para obtener el resto de la información y así sucesivamente con el software o los juegos. Si tiene un valor de ID pero no sabe de qué tipo es, busque en la tabla Medios y el valor Tipo le indicará con cuál de las tres (o más) tablas de datos debe unirse. El punto es que el FK se refiere a a la tabla genérica, no de ella.

Por supuesto, una película, juego o software se puede lanzar en más de un tipo de medio, por lo que puede tener tablas de intersección entre los Media tabla y las respectivas tablas de datos. Otoh, generalmente están etiquetados con diferentes SKU, por lo que es posible que desee tratarlos también como artículos diferentes.

El código, como era de esperar, puede volverse bastante complicado, aunque no tan malo. Otoh, nuestro objetivo de diseño no es la simplicidad del código sino la integridad de los datos. Esto hace que sea imposible mezclar, por ejemplo, datos de juegos con un elemento de película. Y te deshaces de tener un conjunto de campos donde solo uno debe tener un valor y los demás deben ser nulos.