钻石模式:如何(de)规范化?

时间:2012-02-23 18:49:11

标签: sql database schema normalization

假设我们有以下实体:

  • Production Studio
  • 相机操作员
  • 新闻镜头

在这个简单的世界里,制作工作室有许多记者和许多摄影师。每个记者都属于一个工作室。运营商也是如此。新闻片由一位记者和一位操作员制作,两位来自同一个工作室。

这是我将这个模型放入关系数据库的天真方法:

CREATE TABLE production_studios(
  id                   SERIAL PRIMARY KEY,
  title                TEXT NOT NULL
);

CREATE TABLE journalists(
  id                   SERIAL PRIMARY KEY,
  name                 TEXT NOT NULL,
  prodution_studio_id  INTEGER NOT NULL REFERENCES production_studios
);

CREATE TABLE camera_operators(
  id                   SERIAL PRIMARY KEY,
  name                 TEXT NOT NULL,
  production_studio_id INTEGER NOT NULL REFERENCES production_studios
);

CREATE TABLE news_footages(
  id                   SERIAL PRIMARY KEY,
  description          TEXT NOT NULL,
  journalist_id        INTEGER NOT NULL REFERENCES journalists,
  camera_operator_id   INTEGER NOT NULL REFERENCES camera_operators
);

这个架构形成了形状很好的钻石ERD和一些问题。

问题在于新闻片段可以将记者与来自不同制作工作室的摄影师联系在一起。我知道这可以通过编写相应的约束来解决,但为了实验,让我们假装我们在Normal Form数据库设计中进行练习。

  1. 第一个问题是关于术语:说明这个模式是非规范化的是正确的吗?如果是,它会破坏哪种正常形式?或者这个异常是否有更好的名称,如记录间冗余,多路径关系等?

  2. 如何更改此架构以使描述异常不可能?

  3. 当然,我非常感谢提及解决这一具体问题的论文。

1 个答案:

答案 0 :(得分:3)

天真的方式是让你的记者和camera_operators 依赖实体,取决于他们工作的工作室。这意味着生产工作室外键成为其主键的一部分。您的news_footage表的主键包含4个组件:

  • production_studio_id
  • journalist_id
  • camera_operator_id
  • footage_id

和两个外键:

  • journalist_id,production_studio_id,指向记者表,
  • camera_operator,production_studio_id,指向摄像机操作员表

易。

或不是。现在您已经在您的ER模型中定义了相机操作员或记者的存在取决于他们工作的工作室的概念。这并不能很好地反映实际工作:在这种模式中,人们不能改变他们的雇主。

我们不要那样做。

在您的原始模型中,您将与他们扮演的角色(记者或摄影师)混为一谈,并且您错过了一个实际负责制作新闻的短暂实体镜头:[工作室特定的]制作团队。

我的E-R模型看起来像这样:

create table studio
(
  id int not null primary key ,
  title varchar(200) not null ,
)

create table person
(
  id int not null primary key ,
  title varchar(200) not null ,
)

create table team
(
  studio_id          int not null ,
  journalist_id      int not null ,
  camera_operator_id int not null ,

  primary key ( studio_id , journalist_id , camera_operator ) ,

  foreign key ( studio_id          ) references studio ( id ) ,
  foreign key ( journalist_id      ) references person ( id ) ,
  foreign key ( camera_operator_id ) references person ( id ) ,

)

create table footage
(
  studio_id          int not null ,
  journalist_id      int not null ,
  camera_operator_id int not null ,
  id                 int not null ,
  description        varchar(200) not null ,

  primary key ( studio_id , journalist_id , camera_operator_id , id ) ,

  foreign key     ( studio_id , journalist_id , camera_operator_id )
  references team ( studio_id , journalist_id , camera_operator_id ) ,

)

现在,您拥有一个人们可以在不同角色中工作的世界:同一个人可能在某些情境中是摄影师,在其他情境中可能是记者。人们可以改变雇主。特定工作室的团队由记者和摄影师组成。在某些情况下,同一个人可能在团队中扮演两个角色。最后,一个新闻片段由一个且只有一个特定于工作室的团队制作。

这更好地反映了现实世界,而且更加灵活。

编辑添加示例查询:

找到为特定工作室工作的记者:

select p.*
from studio s
join team   t on t.studio_id = s.id
join person p on p.id        = t.journalist_id
where s.title = 'my desired studio name'

这将为您提供与记者角色的工作室相关联的人员组合。但是应该注意到,在现实世界中,人们在一段时间内为雇主工作:正确地建模你需要一个开始/结束日期,你需要用现在的相对概念来限定查询。