PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Polimorfismo em tabelas de banco de dados SQL?


Certo, o problema é que você deseja que apenas um objeto de um subtipo faça referência a qualquer linha da classe pai. A partir do exemplo dado por @Jay S, tente isto:
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 é um exemplo dos subtipos disjuntos mencionados por @mike g.

Re comentários de @Countably Infinite e @Peter:

INSERT para duas tabelas exigiria duas instruções de inserção. Mas isso também é verdade no SQL sempre que você tiver tabelas filhas. É uma coisa comum de se fazer.

UPDATE pode exigir duas instruções, mas algumas marcas de RDBMS suportam UPDATE multi-tabela com sintaxe JOIN, então você pode fazer isso em uma instrução.

Ao consultar dados, você pode fazer isso simplesmente consultando o media table se você precisar apenas de informações sobre as colunas comuns:
SELECT name, url FROM media WHERE media_id = ?

Se você sabe que está consultando um filme, pode obter informações específicas do filme com uma única junção:
SELECT m.name, v.release_date
FROM media AS m
INNER JOIN movies AS v USING (media_id)
WHERE m.media_id = ?

Se você deseja informações para uma determinada entrada de mídia e não sabe de que tipo é, você teria que juntar todas as suas tabelas de subtipos, sabendo que apenas uma dessas tabelas de subtipos corresponderia:
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 = ?

Se a mídia fornecida for um filme, todas as colunas em t.* será NULO.