SQL数据库表中的多态性?

发布于 2024-07-14 00:26:38 字数 622 浏览 6 评论 0原文

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

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

但我对该基本表有多个专业化,例如 tv_series 具有字段 season< /code>、剧集airing,而 movies 表有 release_datebudget > 等等。

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

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

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

I currently have multiple tables in my database which consist of the same 'basic fields' like:

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

But I have multiple specializations of that basic table, which is for example that tv_series has the fields season, episode, airing, while the movies table has release_date, budget etc.

Now at first this is not a problem, but I want to create a second table, called linkgroups with a Foreign Key to these specialized tables. That means I would somehow have to normalize it within itself.

One way of solving this I have heard of is to normalize it with a key-value-pair-table, but I do not like that idea since it is kind of a 'database-within-a-database' scheme, I do not have a way to require certain keys/fields nor require a special type, and it would be a huge pain to fetch and order the data later.

So I am looking for a way now to 'share' a Primary Key between multiple tables or even better: a way to normalize it by having a general table and multiple specialized tables.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

哑剧 2024-07-21 00:26:38

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


@Countically Infinite 和 @Peter 的评论:

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

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

查询数据时,如果您只需要有关公共列的信息,则可以简单地通过查询 media 表来完成:

SELECT name, url FROM media WHERE media_id = ?

如果您知道自己正在查询一部电影,则可以使用单个字段获取特定于电影的信息join:

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。

Right, the problem is you want only one object of one sub-type to reference any given row of the parent class. Starting from the example given by @Jay S, try this:

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

This is an example of the disjoint subtypes mentioned by @mike g.


Re comments by @Countably Infinite and @Peter:

INSERT to two tables would require two insert statements. But that's also true in SQL any time you have child tables. It's an ordinary thing to do.

UPDATE may require two statements, but some brands of RDBMS support multi-table UPDATE with JOIN syntax, so you can do it in one statement.

When querying data, you can do it simply by querying the media table if you only need information about the common columns:

SELECT name, url FROM media WHERE media_id = ?

If you know you are querying a movie, you can get movie-specific information with a single join:

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

If you want information for a given media entry, and you don't know what type it is, you'd have to join to all your subtype tables, knowing that only one such subtype table will match:

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

If the given media is a movie,then all columns in t.* will be NULL.

往日情怀 2024-07-21 00:26:38

考虑使用一个主要的基本数据表,以及从该表延伸出来的带有专门信息的表。

前任。

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

Consider using a main basic data table with tables extending off of it with specialized information.

Ex.

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
送君千里 2024-07-21 00:26:38

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

What you are looking for is called 'disjoint subtypes' in the relational world. They are not supported in sql at the language level, but can be more or less implemented on top of sql.

远山浅 2024-07-21 00:26:38

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

You could create one table with the main fields plus a uid then extension tables with the same uid for each specific case. To query these like separate tables you could create views.

戴着白色围巾的女孩 2024-07-21 00:26:38

使用 Bill Karwin 建议的不相交子类型方法,如何在不必分两步进行的情况下执行插入和更新?

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

谢谢

Using the disjoint subtype approach suggested by Bill Karwin, how would you do INSERTs and UPDATEs without having to do it in two steps?

Getting data, I can introduce a View that joins and selects based on specific media_type but AFAIK I cant update or insert into that view because it affects multiple tables (I am talking MS SQL Server here). Can this be done without doing two operations - and without a stored procedure, natually.

Thanks

命硬 2024-07-21 00:26:38

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

create table some_table (
    name character varying(100),
    description text,
    url character varying(255),
    additional_data json
);

Question is quite old but for modern postresql versions it's also worth considering using json/jsonb/hstore type.
For example:

create table some_table (
    name character varying(100),
    description text,
    url character varying(255),
    additional_data json
);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文