简体   繁体   中英

Database design: foreign keys and normalization

I'm new to database design so please bear with me. I'm using PHP and MySQL. I have a 'movies' table that contains some details about a movie. This includes genres, which have an (if I understand correctly) many to many relationship with movies, implying a single movie can belong to different genres and a single genre can belong to different movies.

From what I gather about database design, storing this kind of relationship in one table is not a good idea as it will either violate First Normal form or Second Normal form rules. How would I design my tables to avoid this; would I have to create a table for each genre separately or... ?

This leads my to my next question: separate tables need to have foreign keys to identify which information belongs to what row. In theory, if I had a unique key identifying each movie which I would then like to use to identify a director in a separate table, how would I create this relationship in MySQL?

Thank you for your time - if I've made anything unclear please let me know and I will try my best to clarify.

This includes genres, which have an (if I understand correctly) many to many relationship with movies, implying a single movie can belong to different genres and a single genre can belong to different movies.

That's right.

From what I gather about database design, storing this kind of relationship in one table is not a good idea

Right. You're looking for something loosely along these lines.

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

For directors, assuming there is only one director per movie, you can use this instead of the movies table above

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

You need one table Movies, one table Genres and one table Movies_and_Genres. The first two contain unique primary keys which you can create using the mysql autoincrement field type. The third table contains pairs of those primary keys.

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

As for the directors, this is a question of data modeling. If a movie can have more than one director, then you need a directors and a movies_and_directors table. Otherwise you need only the directors table and a director column in the movies table.

you need/should use junction tables

table movie:

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

table genre:

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

table director:

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

table movie_genre:

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

table movie_director:

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

You're quite right, what you need here is to have a table of movies (eg tbl_movies );

pk    id
      name
      ... etc

a table for genres (eg tbl_genres );

pk    id
      name
      ... etc

and a table linking the two (eg tbl_movie_genres );

fk    id_movies
fk    id_genres

You can either set the pk of the tbl_movie_geners to be the two foreign keys, or you can set a standalone pk (eg id like in the tbl_movies and tbl_genres tables above).

this way you can list as many genres per movies and they're linked through the tbl_movie_genres table; eg:

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

Would show you that 'Movie 1' is a rom com and 'Movie 2' is an action horror.

To satisfy the many-many relationship use a join table that holds foreign keys to both the movie and genre tables:

MOVIE
-----
ID (PK)

GENRE
-----
ID (PK)

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

Here the MOVIE table has a primary key of ID , the GENRE table has a primary key of ID , and the MOVIE_GENRE table has two foreign key references: one to MOVIE.ID and another to GENRE.ID . The primary key for MOVIE_GENRE could either be the composite key of ( MOVIE_ID , GENRE_ID ) as that will be unique but you could use a synthetic key as well.

For dealing with the director table and relationship, if it is a one-to-many relationship (one director for many movies), simply add a foreign key to the MOVIE table:

DIRECTOR
--------
ID (PK)

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

If the off chance you need to support another many-to-many relationship (many directors for many movies), use the join table approach like above.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM