创建相关表以避免可能的空字段

时间:2018-09-01 20:27:56

标签: mysql sql database-design

假设我有一个名为 movie_celebrity 的表,该表具有以下列:

CREATE TABLE `movie_celebrity` (
  `id` int(11) NOT NULL,
  `movie_id` int(11) NOT NULL,
  `celebrity_id` int(11) NOT NULL,
  `movie_celebrity_type_id` int(11) NOT NULL,
  `role` varchar(10) DEFAULT NULL,
  `character_name` varchar(50) DEFAULT NULL
)

因此,如果名人的类型是作家导演,则rolecharacter_name字段将为空,只有类型为演员,该字段将被填写。

这是一个非常糟糕的设计吗?还是效率低下?
我认为为此两列创建一个单独的表会更好。

编辑(包括架构)

电影表:

CREATE TABLE `movie` (
  `id` int(11) NOT NULL,
  `name` varchar(100) NOT NULL,
  `poster` varchar(255) DEFAULT NULL,
  `release_Date` date NOT NULL,
  `runtime` time NOT NULL,
  `storyline` text NOT NULL,
  `rated` varchar(10) DEFAULT NULL,
  `rating` float(2,1) NOT NULL DEFAULT '0.0',
  `inserted` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
)

名人表:

CREATE TABLE `celebrity` (
  `id` int(11) NOT NULL,
  `name` varchar(100) NOT NULL,
  `picture` varchar(255) DEFAULT NULL,
  `date_of_birth` date NOT NULL,
  `biography` text NOT NULL
)

电影名人表:

CREATE TABLE `movie_celebrity` (
  `id` int(11) NOT NULL,
  `movie_id` int(11) NOT NULL,
  `celebrity_id` int(11) NOT NULL,
  `type` varchar(10) NOT NULL,
  `role` varchar(10) DEFAULT NULL,
  `character_name` varchar(50) DEFAULT NULL
)

1 个答案:

答案 0 :(得分:1)

似乎您正在尝试制作一个“广播和剧组”组合表。根据您使用它的方式,将它们全部合并在一个表中可能是一个好主意,或者最好单独使用“ cast”和“ crew”。我想从一个组合表开始,看看它是如何进行的。如果仍然无法解决问题,则可以拆分表和create a view以实现向后兼容。

根据作者的评论,movie_celebrity_type_id用于诸如“作家”或“演员”或“导演”之类的事物,而role用于“领导”或“支持”之类的事物。这似乎很奇怪。许多电影没有定义“主打”还是“支持”演员表。许多名人是目录,作家,演员和制片人。阿尔弗雷德·希区柯克就是一个很好的例子。

您的moviecelebrity表很好,尽管我可能只将它们称为persons。我会像这样设计连接他们的桌子:

create table cast_and_crew (
    id integer primary key auto_increment,
    movie_id integer not null,
    celebrity_id integer not null,
    role text not null,
    character_name text,
    credited boolean not null default true,
    notes json not null default '{}'

    foreign key(movie_id) references movie(id),
    foreign key(celebrity_id) references celebrity(id),

    -- Include the character name for people who act in more than one role
    unique(movie_id, celebrity_id, role, character_name)
);

这不仅仅是一个电影/名人联接表,所以我给它起了描述性的名称cast_and_crew。由于绝大多数条目将是带有character_name的参与者,因此最好将其设为真实的列。 notes JSON column为数据的任何其他位提供了灵活性,而无需添加更多列。

例如,阿尔弗雷德·希区柯克(Alfred Hitchcock)在The Birds ...中的失信露面……

insert into cast_and_crew (movie_id, celebrity_id, role, character_name, credited)
    values(<The Birds>, <Alfred Hitchcock>, 'actor', 'Man Walking Dogs Out of Pet Shop', false);

<The Birds><Alfred Hitchcock>是它们各自的ID。

然后再次担任制片人和导演。

insert into cast_and_crew (movie_id, celebrity_id, role)
    values(<The Birds>, <Alfred Hitchcock>, 'producer');

insert into cast_and_crew (movie_id, celebrity_id, role)
    values(<The Birds>, <Alfred Hitchcock>, 'director');

阿尔弗雷德·希区柯克(Alfred Hitchcock)的助手佩吉·罗伯逊(Peggy Robertson)可能会像这样利用notes列。

insert into cast_and_crew (movie_id, celebrity_id, role, noes)
    values(<The Birds>, <Peggy Robertson>, 'assistant', '{ "to": <Alfred Hitchcock> }');

使用该表的代码可以编写为基于角色实例化子类。例如,您可以编写一个通用的CastAndCrew类。然后,CastAndCrew::Actor子类将提供name方法并要求对其进行定义。 CastAndCrew::Assistant会在to中寻找notes字段。

另一个例子是雷·伯威克(Ray Berwick)被誉为“鸟类训练者”。您可以输入role = 'trainer of the birds',但如果要搜索所有动物训练员怎么办?您可以具有普通语和规范化角色,普通语为“鸟类的训练者”,规范化的角色为“动物训练者”。取决于您要完成的任务。

可能会有更多改进,但是它们取决于您要对数据做什么。