Database design: foreign keys and normalization - php

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 (e.g. 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 (e.g 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.

Related

Needing help storing dynamic list in mySQL

I am working on a project where I need to store an unknown length list on names in an sql db. It will be a list of students in a class, which will be different for each class. I also need to be able to search for them (in PHP/SQL) by student name to see all the classes a student attended. I was thinking about storing the class as a row and the students as an array, but I can't figure out an sql to query the arrays in the db. Am I heading the right direction? Maybe creating a new db row for each student for each class? Maybe making the students rows and update an array of classes for each? I will probably using AJAX later to retrieve the info. Thanks!
Why don't you create two tables to store the information about existing Classes and Students and a relation-table Participant that stores the information about which student goes to which class?
Something along the lines of:
CREATE TABLE Classes (
id int NOT NULL,
description varchar(200),
PRIMARY KEY (id)
)
CREATE TABLE Studentes (
id int NOT NULL,
name varchar(200),
PRIMARY KEY (id)
)
CREATE TABLE Participant (
student_id int NOT NULL,
class_id int NOT NULL,
FOREIGN KEY (student_id) REFERENCES Students(id)
FOREIGN KEY (class_id) REFERENCES Classes(id)
)
Then later, you can find out what classes a students visits with a SQL-query like:
SELECT c.description
FROM Students s
LEFT JOIN Participant p ON (s.id = p.student_id)
LEFT JOIN Classes c ON (p.class_id = c.id)
WHERE s.name = 'SilverSlug'
;
What you are looking for is a relations table. It will keep track of class and students. Example
Classes Table : table of all the classes
ID = Primary key
|ID | Name |
| 1 | Math |
Students Table : table of all the students
ID = Primary key
|ID | Name |
| 1 | Sam |
| 2 | Tom |
Relations Table : Used to keep track of an instance of a class
ID = Primary key Class_ID & Student_ID are Secondary keys
|ID | Class_ID | Student_ID | Time |
| 1 | 1 | 1 | 6am |
| 2 | 1 | 2 | 6am |
With these tables you can make simple queries to find out who's in what class, you can also find out what classes a student has.

Design relationship in mysql

I want to design an application, where we can add many category and each category can have a parameters. And I want to create a new product to the category and her parameters. Relations between
parameters and category is many-to-many (categories_table, parameters_table)
Category "Test" parameters:
id | key | type | def_value |
==============================
1 | color | text | red
==============================
2 | serial| text | 0
etc.
And now i want to create a new product with those parameters, so i have a question. Should i simply create many-to-many or maybe create new table with records like parameters ? Ex,
test1_table -> color, srial, etc.,
Or
products -> parameter_id,value
cause the relationship is many to many you have to create another table with the columns that are the foreign keys in the relation ---
tip: because you will have a table called category and each category can have parameters you should create another table with a foreign key that have the parameters
example
table_category - record 1 :color
table category_parameters - record
1 : color,azul -- record 2 : color,verde etc
and the foreign key is the primary key of category in this case ('COLOR')

Keyword Functionality like Stackoverflows

I have several entries (that will grow into thousands) in a database that I want to be able to index via keywords.
So say I have a table such as:
id | username | email | description
And I want to attach multiple keywords to that user such as:
Tall | Blonde | Male | Skinny
How would I structure the table for that? Much like the keywords used in stackoverflow at the bottom of the new question?
Thanks
you need three tables
users:
id | username | email | description
tags: (will contain Tall, Blonde, Male, Skinny etc... in the name field)
id | name
users_tags:
user_id | tag_id
to make a user have a tag, you add a row to the users_tags table with the ids of the associated items.
both user_id and tag_id should be foreign keys, referring to the appropriate table, and combined, they should form a unique key (possibly primary key).
If I understood correctly, have 3 tables:
- users (user_id, username)
- keywords (keyword_id, keyword)
- user_keywords (user_id, keyword_id)
and have relations between them (on same column names as of in an example).
This is a many-to-many relationship.
You have a table of keywords and a table of objects (which can be associated with keywords).
You then have a third table which has two columns which form a composite key, each of which is a foreign key on on of the other two tables.
e.g.
object_keyword_relationship
===========================
object_id | keyword_id
1 | 1
1 | 2

What is a Parent table and a Child table in Database?

I just want to know what is a parent table and what is a child table in databases. Can you please show me an example so I understand how it works please.
Thank You
Child tables and parent tables are just normal database tables, but they’re linked in a way that's described by a parent–child relationship.
It’s usually used to specify where one table’s value refers to the value in another table (usually a primary key of another table).
For example, imagine a news article. This could be represented by a table called articles and has fields for id, headline, body, published_date and author. But instead of placing a name in the author field, you could instead put the ID value of a user in a separate table—maybe called authors—that has information on authors such as id, name, and email.
Therefore, if you need to update an author’s name, you only need to do so in the authors (parent) table; because the articles (child) table only contains the ID of the corresponding author record.
Hope this helps you understand better.
Be aware you can have relationships that appear to be parent-child but are not, for instance when lookup tables are being used. The distinction is that in a true parent-child relationship, records typically don't stand are their own very well - they are detail records for the parent and are not useful without the parent table info. A person can own multiple cars in the DMV database, but you wouldn't want records in the CARS table without a parent record in the OWNERS table - it would be nearly useless data.
On the other hand, if I am using a lookup table to expand a code to something more meaningful, or to constrain data entry to acceptable values, then the "child" record can still useful (can stand alone) if the lookup table is deleted. I could still have the sex information as "M" or "F" even if I no longer have the lookup table to expand that to "Male" or "Female".
Parent - The entity on the "one" (/1) side of a relation with another table
Child - The entity on the "many" (/N/*) side of a relation with another table
A child table tends to be one where it has one or more foreign keys pointing at some other table(s). Note that a child table can itself be a parent to some OTHER table as well.
Those terms are used in database relationships.
for example u have two table,
1.Manifast
+-------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------------+------+-----+---------+----------------+
| manifast_id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| description | text | NO | | NULL | |
| title | text | NO | | NULL | |
+-------------+------------------+------+-----+---------+----------------+
day_sequence
+-----------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+------------------+------+-----+---------+----------------+
| day_sequence_id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| day_number | int(11) | NO | | NULL | |
| day_start | int(11) | NO | | NULL | |
| manifast_id | int(11) | NO | | NULL | |
+-----------------+------------------+------+-----+---------+----------------+
if u want to connect those two tables,u need to use the command with following format.
> ALTER TABLE child_table_name ADD FOREIGN KEY (P_ID) REFERENCES
> parent_table_name (P_ID)
and so it become.
> ALTER TABLE day_sequence ADD CONSTRAINT fk_manifast FOREIGN KEY
> (manifast_Id) REFERENCES manifast(manifast_Id);
In summary,
Child table is a table which has foreign key,and is connected from others table.
Parent table has no foreign key and connect to other.
[ Note : This ans is just for connecting two tables ]

MySQL inner join on two columns

I have two tables, books and authors. books has a author_id column and a secondary_author_id column (no books have more than two authors). I'm so far doing:
SELECT * FROM books
LEFT JOIN authors
ON books.author_id=authors.id
which is handling the join with the first author. I can't work out how I'd handle the secondary author though. Should I change my schema, or do I just need a bit of SQL help?
SELECT books.*, author1.*, author2.*
FROM books
LEFT JOIN author AS author1
ON author1.author_id = books.author_id
LEFT JOIN author AS author2
ON author2.author_id = books.secondary_author_id
In SQL, you can alias the tables by adding it after the table name. Just be careful, now you'll have duplicate columns, so instead of author1.* you will probably want to alias the results of both author1 and author2.
EDIT
Additional details -- Say you have your basic table (i'll include the details so if people want to test on their own they can):
CREATE DATABASE test;
USE test;
CREATE TABLE books
(
book_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(50),
author_id INT NOT NULL,
secondary_author_id INT
);
CREATE TABLE authors
(
author_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50)
);
INSERT INTO authors (author_id,name) VALUES (1,'Sue Z. Que'),(2,'John Doe'),(3,'Bob Smith');
INSERT INTO books (book_id,title,author_id,secondary_author_id) VALUES (1,'JOIN-ing Two Tables',1,2);
If you do the select I mention above, your result will be the following:
|----------------------- books TABLE -----------------------------|---- authors table -----|---- authors table ---|
+---------+---------------------+-----------+---------------------+-----------+------------+-----------+----------+
| book_id | title | author_id | secondary_author_id | author_id | name | author_id | name |
+---------+---------------------+-----------+---------------------+-----------+------------+-----------+----------+
| 1 | JOIN-ing Two Tables | 1 | 2 | 1 | Sue Z. Que | 2 | John Doe |
+---------+---------------------+-----------+---------------------+-----------+------------+-----------+----------+
(I've added the top header just for calrity's sake) you see you have two author_id's and two name's (as they are joins of the same table and same column names). BUT, if you alias the columns from the joins like so:
SELECT books.*, author1.name AS primary_author, author2.name AS secondary_author
FROM books
LEFT JOIN authors AS author1
ON author1.author_id = books.author_id
LEFT JOIN authors AS author2
ON author2.author_id = books.secondary_author_id;
You get a much cleaner result:
|----------------------- books TABLE -----------------------------| authors table -|- authors table --|
+---------+---------------------+-----------+---------------------+----------------+------------------+
| book_id | title | author_id | secondary_author_id | primary_author | secondary_author |
+---------+---------------------+-----------+---------------------+----------------+------------------+
| 1 | JOIN-ing Two Tables | 1 | 2 | Sue Z. Que | John Doe |
+---------+---------------------+-----------+---------------------+----------------+------------------+
SELECT books.* FROM books, authors.name, secondary_authors.name
LEFT JOIN authors
ON books.author_id=authors.id
LEFT JOIN authors as secondary_authors
ON books.secondary_author_id=secondary_authors.id
You need to rethink your design, because one day there will be a book with three authors, and the next day there will be a book with zero. (I've been there myself.)
Edit
As your comment says: yes, you need a books_authors table. As long as you have your indexes set up properly, it's not a big performance hit.
The most annoying part is that you're often going to want to string the authors together (one entry per book, concatenating all the authors into a single column). You'll probably end up creating a view for that.
just do another join on the secondary id

Categories