目前,我的数据库中有多个由相同的"基本字段"组成的表,如:

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

但我对这个基本表有多个专门化,例如,tv_series有字段seasonepisodeairing,而movies表有字段release_datebudget等等.

现在一开始这不是问题,但我想创建第二个表,名为linkgroups,带有这些专用表的外键.这意味着我必须在某种程度上使它自身正常化.

我听说过解决这个问题的一种方法是用一个key-value对表对其进行规范化,但我不喜欢这个 idea ,因为它是一种"数据库中的数据库"方案,我没有办法要求某些键/字段,也不需要特殊类型,而且以后获取和排序数据会非常困难.

所以我现在正在寻找一种在多个表之间"共享"主键的方法,或者更好的方法:通过拥有一个通用表和多个专用表来规范主键.

推荐答案

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

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的不相交子类型mentioned的一个例子.


@countablely Infinite和@Peter的重新 comments :

INSERT到两个表需要两个INSERT语句.但在SQL中,只要有子表,这也是正确的.这是一件平常的事.

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

查询数据时,如果只需要有关公共列的信息,只需查询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.*中的所有列都将为空.

Postgresql相关问答推荐

无法在PostgreSQL中创建方案和表

仅使用 ssl 连接到 Postgresql 数据库

使用FastAPI和PostgreSQL进行测试

PostgreSQL pg_dump 创建 sql 脚本,但它不是 sql 脚本:有没有办法让 pg_dump 创建标准的 sql 脚本?

PostgreSql maintenance_work_mem 在索引创建期间增加

用于生产的 Rails 性能调优?

运算符不存在:integer = integer[] 在使用 ANY 的查询中

如何将 postgres 数据库转换为 sqlite

Windows PSQL 命令行: is there a way to allow for passwordless login?

!= 和 <> 运算符有什么区别?

是否可以在 Postgres 中存储一个 1 字节的数字?

如何将两个 PostgreSQL 列聚合到一个用括号分隔的数组

MAC OS X 上的 Postgres 权限被拒绝

Redis 可以写出到像 PostgreSQL 这样的数据库吗?

大型查询后 psycopg2 泄漏内存

Postgres Npgsql 连接池

SQL 基本类型:integer vs int?

Oracle 相当于 Postgres 的 DISTINCT ON?

Android 的 JDBC 与 Web 服务

重命名 Amazon RDS 主用户名