【问题标题】:Database design: foreign keys and normalization数据库设计:外键和规范化
【发布时间】:2012-08-10 18:09:03
【问题描述】:

我是数据库设计的新手,所以请多多包涵。我正在使用 PHP 和 MySQL。 我有一个“电影”表,其中包含有关电影的一些详细信息。这包括流派,它与电影具有多对多关系(如果我理解正确的话),这意味着一部电影可以属于不同的流派,而一个流派可以属于不同的电影。

根据我收集到的有关数据库设计的信息,将这种关系存储在一个表中并不是一个好主意,因为它会违反第一范式或第二范式规则。 我将如何设计我的桌子来避免这种情况;我必须为每种类型分别创建一个表格还是...?

这引出了我的下一个问题:单独的表需要有外键来识别哪些信息属于哪一行。理论上,如果我有一个唯一的密钥来标识每部电影,然后我想用它来标识单独表中的导演,我将如何在 MySQL 中创建这种关系?

感谢您抽出宝贵时间 - 如果我有任何不清楚的地方,请告诉我,我会尽力澄清。

【问题讨论】:

    标签: php mysql database database-design


    【解决方案1】:

    这包括类型,它们有很多(如果我理解正确的话) 与电影有很多关系,暗示一部电影可以属于 到不同的流派,一个流派可以属于不同的电影。

    没错。

    根据我收集到的关于数据库设计的信息,存储这种 一张表的关系不是一个好主意

    没错。你正在寻找一些松散的东西。

    create table movies (
      movie_id integer primary key
      -- other columns
    );
    
    create table genres (
      genre varchar(15) primary key
      -- other columns?
    );
    
    create table movie_genres (
      movie_id integer not null,
      genre varchar(15) not null,
      primary key (movie_id, genre),
      foreign key (movie_id) references movies (movie_id),
      foreign key (genre) references genres (genre)
    );
    

    对于导演,假设每部电影只有一个导演,您可以使用它来代替上面的电影表

    create table movies (
      movie_id integer primary key,
      director_id integer not null,
      foreign key (director_id) references directors (director_id) -- not shown.
      -- other columns
    );
    

    【讨论】:

    • 感谢您提供出色而全面的答案,特别感谢您涵盖外键问题。
    【解决方案2】:

    您需要一张表 Movies、一张表 Genres 和一张表 Movies_and_Genres。前两个包含唯一的主键,您可以使用 mysql 自动增量字段类型创建它们。第三个表包含这些主键对。

    create table movies (id integer not null primary key auto_increment, title ... );
    create table genres (id integer not null primary key auto_increment, genre ... );
    create table movies_and_genres (id_movie integer not null, id_genre integer not null);
    

    对于导演来说,这是一个数据建模的问题。如果一部电影可以有多个导演,那么您需要一个 director 和一个 movies_and_directors 表。否则,您只需要 director 表和 movies 表中的 director 列。

    【讨论】:

      【解决方案3】:

      你需要/应该使用junction tables

      表格电影:

      | id | title | rating |
      -----------------------
      | 1  | foo   |   5    |
      | 2  | bar   |   4    |
      

      表格类型:

      | id | name    | 
      ----------------
      | 1  | comedy  |
      | 2  | romance |
      

      导演:

      | id | name    | 
      ----------------
      | 1  | hello   |
      | 2  | world   |
      

      表格电影类型:

      | id | movie_id | genre_id |
      ----------------------------
      | 1  |     1    |     1    |
      | 2  |     1    |     2    |
      | 3  |     2    |     1    |
      

      表格电影导演:

      | id | movie_id | director_id |
      -------------------------------
      | 1  |     1    |     1       |
      | 2  |     2    |     1       |
      | 3  |     2    |     2       |
      

      【讨论】:

        【解决方案4】:

        你说的很对,你需要的是有一个电影表(例如tbl_movies);

        pk    id
              name
              ... etc
        

        类型表(例如tbl_genres);

        pk    id
              name
              ... etc
        

        和一个连接两者的表格(例如tbl_movie_genres);

        fk    id_movies
        fk    id_genres
        

        您可以将tbl_movie_geners 的pk 设置为两个外键,也可以设置一个独立的pk(例如id,如上面的tbl_moviestbl_genres 表)。

        通过这种方式,您可以为每部电影列出尽可能多的类型,并通过tbl_movie_genres 表链接它们;例如:

        tbl_movies:
        id    name
        1     Movie 1
        2     Movie 2
        
        tbl_genres:
        id    name
        1     Horror
        2     Action
        3     Rom Com
        
        tbl_movie_genres
        id_movies    id_genres
        1            3
        2            1
        2            2
        

        会告诉你“电影 1”是一部 rom com,而“电影 2”是一部动作恐怖片。

        【讨论】:

          【解决方案5】:

          要满足多对多关系,请使用包含电影表和流派表的外键的连接表:

          MOVIE
          -----
          ID (PK)
          
          GENRE
          -----
          ID (PK)
          
          MOVIE_GENRE
          -----------
          MOVIE_ID (FK that references MOVIE(ID))
          GENRE_ID (FK that references GENRE(ID))
          

          这里MOVIE 表有一个主键IDGENRE 表有一个主键IDMOVIE_GENRE 表有两个外键引用:一个到MOVIE.ID 和另一个给GENRE.IDMOVIE_GENRE 的主键可以是 (MOVIE_ID,GENRE_ID) 的复合键,因为这将是唯一的,但您也可以使用合成键。

          对于director表和关系的处理,如果是一对多的关系(一个导演多部电影),只需在MOVIE表中添加外键即可:

          DIRECTOR
          --------
          ID (PK)
          
          MOVIE
          -----
          ID (PK)
          DIRECTOR_ID (FK TO DIRECTOR(ID))
          

          如果您需要支持另一个多对多关系(多部电影的多位导演),请使用上面的连接表方法。

          【讨论】: