23

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

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

但是我对该基本表有多个专业化,例如tv_series具有字段season, episode, airing, 而movies表具有release_datebudget

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

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

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

4

7 回答 7

26

对,问题是您只希望一种子类型的一个对象引用父类的任何给定行。从@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)
);

这是@mike g提到的不相交子类型的一个示例。


回复@Countably Infinite 和@Peter 的评论:

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

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

查询数据时,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。

于 2009-02-18T17:18:08.530 回答
8

考虑使用一个主要的基本数据表,其中包含专门信息的表格。

前任。

basic_data
id int,
name character varying(100),
description text,
url character varying(255)


tv_series
id int,
BDID int, --foreign key to basic_data
season,
episode
airing


movies
id int,
BDID int, --foreign key to basic_data
release_data
budget
于 2009-02-18T15:47:56.407 回答
3

由于您标记了此 PostgreSQL,您可以查看http://www.postgresql.org/docs/8.1/static/ddl-inherit.html但要注意警告。

于 2009-02-18T23:06:26.197 回答
2

您正在寻找的东西在关系世界中被称为“不相交的子类型”。它们在语言级别的 sql 中不受支持,但可以或多或少地在 sql 之上实现

于 2009-02-18T17:03:27.753 回答
1

您可以创建一个包含主要字段和一个 uid 的表,然后为每个特定情况创建具有相同 uid 的扩展表。要像单独的表一样查询这些,您可以创建视图。

于 2009-02-18T15:44:56.977 回答
1

使用 Bill Karwin 建议的不相交子类型方法,您将如何执行 INSERT 和 UPDATE 而无需分两步执行?

获取数据,我可以引入一个基于特定 media_type 连接和选择的视图,但是我无法更新或插入该视图,因为它会影响多个表(我在这里说的是 MS SQL Server)。这可以在不进行两次操作的情况下完成吗 - 自然也不需要存储过程。

谢谢

于 2010-05-13T00:51:36.317 回答
1

问题已经很老了,但对于现代 postresql 版本,也值得考虑使用 json/jsonb/hstore 类型。例如:

create table some_table (
    name character varying(100),
    description text,
    url character varying(255),
    additional_data json
);
于 2015-05-05T13:10:21.263 回答