sql - SQL 数据库表中的多态性?

标签 sql postgresql database-normalization

目前我的数据库中有多个表,它们包含相同的“基本字段”,例如:

name character varying(100),
description text,
url character varying(255)

但我对该基本表有多个特化,例如 tv_series 具有字段 seasonepisode airing,而 movies 表有 release_datebudget

起初这不是问题,但我想创建第二个表,称为 linkgroups,并带有这些专用表的外键。这意味着我必须以某种方式在其内部对其进行规范化。

我听说过解决这个问题的一种方法是使用 key-value-pair-table 对其进行规范化,但我不喜欢这个想法,因为它有点像“数据库内” -a-database' 方案,我没有办法要求某些键/字段,也不需要特殊类型,以后获取和排序数据将是一个巨大的痛苦。

所以我现在正在寻找一种在多个表之间“共享”主键的方法,甚至更好:一种通过拥有一个通用表和多个专用表来对其进行规范化的方法。

最佳答案

是的,问题是您只希望一种子类型的一个对象引用父类的任何给定行。从 example 开始由@Jay S 给出,试试这个:

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

这是不相交子类型的示例 mentioned由@mike g 提供。


@Countably Infinite 和@Peter 的评论:

插入两个表需要两个插入语句。但只要您有子表,在 SQL 中也是如此。这是一件很平常的事情。

UPDATE 可能需要两条语句,但某些品牌的 RDBMS 支持使用 JOIN 语法的多表 UPDATE,因此您可以在一条语句中完成。

查询数据时,如果只需要公共(public)列的信息,只需查询media表即可:

SELECT name, url FROM media WHERE media_id = ?

如果您知道您正在查询一部电影,您可以通过一次连接获取特定于电影的信息:

SELECT m.name, v.release_date
FROM media AS m
INNER JOIN movies AS v USING (media_id)
WHERE m.media_id = ?

如果您想要一个给定媒体条目的信息,但您不知道它是什么类型,您必须连接到所有子类型表,知道只有一个这样的子类型表会匹配:

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 = ?

如果给定的媒体是电影,则 t.* 中的所有列都将为 NULL。

关于sql - SQL 数据库表中的多态性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/561576/

相关文章:

database - 在数据库列中存储分隔列表真的那么糟糕吗?

.net - 我们应该对数据库进行反规范化以提高性能吗?

sql - 加入多个表/约束或 has_one_through 与次要约束

PHP - 如何在准备好的语句中将数组替换为主机参数

postgresql - 将 PostgreSQL 9.0 注册并运行为 Windows 服务

postgresql - 重复的单个数据库记录

sql - 从具有差异的 varchar 列计算年龄

mysql - 选择使用不同的 mysql 进行更新

sql - 更新第一个匹配行

mysql - 规范化 SQL - 根据另一个表中的匹配字符串将列设置为主键标识符