Correcto, el problema es que desea que solo un objeto de un subtipo haga referencia a cualquier fila dada de la clase principal. A partir del ejemplo dado por @Jay S, intente esto:
create table media_types (
media_type int primary key,
media_name varchar(20)
);
insert into media_types (media_type, media_name) values
(2, 'TV series'),
(3, 'movie');
create table media (
media_id int not null,
media_type not null,
name varchar(100),
description text,
url varchar(255),
primary key (media_id),
unique key (media_id, media_type),
foreign key (media_type)
references media_types (media_type)
);
create table tv_series (
media_id int primary key,
media_type int check (media_type = 2),
season int,
episode int,
airing date,
foreign key (media_id, media_type)
references media (media_id, media_type)
);
create table movies (
media_id int primary key,
media_type int check (media_type = 3),
release_date date,
budget numeric(9,2),
foreign key (media_id, media_type)
references media (media_id, media_type)
);
Este es un ejemplo de los subtipos disjuntos mencionados por @mike g.
Re comentarios de @Countably Infinite y @Peter:
INSERTAR en dos tablas requeriría dos declaraciones de inserción. Pero eso también es cierto en SQL cada vez que tiene tablas secundarias. Es algo normal de hacer.
UPDATE puede requerir dos declaraciones, pero algunas marcas de RDBMS admiten UPDATE de varias tablas con sintaxis JOIN, por lo que puede hacerlo en una sola declaración.
Al consultar datos, puede hacerlo simplemente consultando los media
tabla si solo necesita información sobre las columnas comunes:
SELECT name, url FROM media WHERE media_id = ?
Si sabe que está consultando una película, puede obtener información específica de la película con una sola unión:
SELECT m.name, v.release_date
FROM media AS m
INNER JOIN movies AS v USING (media_id)
WHERE m.media_id = ?
Si desea información para una entrada de medios determinada y no sabe de qué tipo es, debe unirse a todas sus tablas de subtipos, sabiendo que solo una de esas tablas de subtipos coincidirá:
SELECT m.name, t.episode, v.release_date
FROM media AS m
LEFT OUTER JOIN tv_series AS t USING (media_id)
LEFT OUTER JOIN movies AS v USING (media_id)
WHERE m.media_id = ?
Si el medio dado es una película, entonces todas las columnas en t.*
será NULL.