我的数据结构怎么样?

时间:2012-02-04 18:25:05

标签: mysql sql database database-design data-structures

我整理了一个简单的数据库,用于存储有关奖项和提名的信息。我试图尽可能多地删除数据冗余。以下是它目前的看法:

enter image description here

提名表的原因是我意识到一个提名会有很多被提名者。例如,奖励Best Screenplay可以转到Ken Levine and David IsaacsWoody AllenJoss Whedon, Andrew Stanton, Joel Cohen and Alec Sokolow

注意:Award.name是奖励的名称,例如: Best Actor

感谢您指出任何可能的改进。

2 个答案:

答案 0 :(得分:2)

NOMINATED表在NOMINEESNOMINATIONS之间创建m:n关系。删除其NominatedID列,并使用两列NomineeIDNominationID作为主键。这可以防止同一人在同一提名中被提名两次。

 NOMINEES               NOMINATED
+---------------+      +---------------------+      NOMINATIONS
| PK  NomineeID |<----o| PK FK  NomineeID    |     +------------------+
+---------------+      | PK FK  NominationID |o--->| PK  NominationID |
|     Name      |      +---------------------+     +------------------+
+---------------+                                  | FK  FilmID       |
                                                   | FK  AwardID      |
                                                   | FK  EventID      |
                                                   +------------------+

答案 1 :(得分:1)

次要说明

  1. 我更喜欢表格和列名称的单数形式,因此Nominees变为NomineeAwards变为Award等等。

  2. Award表重命名为AwardCategory,以@wildplasser在评论中建议。


  3. 主要说明

    正如@Olivier指出的那样,m::n关系中间表(如Nominated个)将对化合物UNIQUE产生(NomineeId, NominationId)约束。因此,最好删除自动生成的(代理)键并使复合键为PRIMARY KEY。这是关系的natural key,使用它作为主键有几个优点。在这种情况下,surrogate key完全没有任何意义,除了有更宽的行和一个更无用的索引。无论如何,自然键的两部分将用于连接。

    同样的事情适用于Nomination表!复合(FilmId, AwardCategoryId, EventId)将是UNIQUE密钥,以确保同一事件的同一奖项类别的电影不会获得2次提名,因此再次删除代理键并使此化合物成为主要内容会更好键。反思,我们可能会为同一部电影的同一奖项类别提名2项提名,比如两个'Best Supporting Actor',所以我们在主键中添加NominatioNo(如果我们想要限制提名,这可以很方便对于某个类别或所有人都说常数5)。

    现在,(有趣且有趣的)事情是Nominated表必须重新检查并具有复合(NomineedId, FilmId, AwardCategoryId, EventId)主键 - 并且只有这4列作为属性。

    我不确定EventCeremony表到底要存储的是什么,但我们假设Ceremony表用于存储有关不同仪式的信息(例如'Oscar Awards''Strawberry Awards')和Event表用于存储有关一年仪式的信息(例如('Oscar', 2011), ('Oscar', 2012), ('Starwberry Awards', 2012))。因此,我会将Year移至Event表,并将(CeremonyId, EventYear)作为事件的Priamry Key。 (我很可能错了,你更了解你的数据。)。

    因此,Nomination.EventId已被CeremonyIdEventYear取代,NominationNominated的主要密钥会更长! (这是使用自然键作为主键的一个缺点)。让我们看看到目前为止我们得到了什么:

    Database Design 1 http://img594.imageshack.us/img594/9592/oscarw.png

    您可以轻松地将NominationWinner(作为1:1关系的表格添加到Nomination)来存储哪个提名赢得了哪个类别((CeremonyId, EventYear, AwardCategoryId)上的唯一约束将强制执行那)。设计将是这样的:

    Database Design 1 http://img845.imageshack.us/img845/2108/oscar3x.png

    拥有如此复杂的主键可能看起来很笨拙,但在连接表时会有所帮助。想象一下,你想找到50岁和60岁的“草莓奖”的所有获奖者,并且只为“女演员”类别找到奖项,并展示该奖项的电影。您不必加入所有中间表。相反,您只能使用NominationWinnerNomineeCeremonyFilmAwardCategory表(并且仅使用Nominated个中间版来检索数据表):

    SELECT ne.Name                AS Winner
         , wi.EventYear           AS Year
         , aw.AwardCategoryTitle  AS Category
         , fm.Title               AS FilmTitle
    FROM
          NominationWinner AS wi
      JOIN 
          Ceremony AS ce
              ON ce.CeremonyId = wi.CeremonyId 
      JOIN
          AwardCategory AS aw
              ON aw.AwardCategoryId = wi.AwardCategoryId 
      JOIN
          Film AS fm
              ON fm.FilmId = wi.FilmId 
      JOIN
          Nominated nd
              ON  nd.CeremonyId    = wi.CeremonyId 
              AND nd.EventYear     = wi.EventYear 
              AND nd.AwardCategory = wi.AwardCategory 
              AND nd.NominationNo  = wi.NominationNo 
              AND nd.FilmId        = wi.FilmId  
      JOIN
          Nominee AS ne
              ON ne.NomineeId = nd.NomineeId 
    WHERE 
          ce.CeremonyTitle = 'Strawberry Awards'
      AND wi.EventYear BETWEEN 1950 AND 1969
      AND aw.AwardCategoryTitle LIKE '%Actress%'