I am currently learning database for an upcoming school semester, So I'm practicing with the books I currently have. I have books by multiple authors and authors with multiple books. Also books with multiple categories.
So I made three tables. A books table (with all the books information, including the author), an authors table (with the authors name, address, ect) and a categories table (since some books have multiple categories). Since some books have multiple authors and some authors have multiple books, I made a junction table called AuthorsBooks and filled it with information. By best practice, is it ok to NOT put authors with only one book in that (AuthorsBooks) table? Also, I created a BooksCategory junction table and put the books with multiple categories into that table. What would be the best way to link those two tables? By book title? Thanks.
In general your approach sounds correct with a few exceptions.
So I made three tables
Here's my count, based on your descriptions:
Authors
Books
Categories
AuthorsBooks
BooksCategories
A books table (with all the books information, including the author)
This is incorrect. At the point you realized you need AuthorsBooks, there is no reason to have author as part of the Books table. Any column(s) you used to implement that should be removed from Books.
By best practice, is it ok to NOT put authors with only one book in
that (AuthorsBooks) table?
Absolutely not. You created the right structure with AuthorsBooks. It supports any number of authors for a book.
Also, I created a BooksCategory junction table and put the books with
multiple categories into that table. What would be the best way to
link those two tables?
By Keys. Every table should have a primary key, and in your case the keys should be integers that get incremented with each new row.
Here's an outline of the table structure and standard naming.
Books
-----
id integer auto_increment primary key
title varchar(150)
Categories
----------
id integer auto_increment primary key
name varchar(60)
BooksCategories
---------------
books_id integer primary key (foreign key for Books.id)
categories_id integer primary key (foreign key for Categories.id)
Related
I have the following album table:
album_id(PK)
album_name
artist_name
year
songs
My candidate keys are {id} and {album_name, artist_name}.
Now I am going to normalize the table till 3NF, and I would like to know the reason behind the data of artist_name column being redundant.
1NF
Goal: columns should be atomic.
Result:
album:
album_id(PK)
album_name
artist_name
year
song:
song_id(PK)
album_id(FK)
song_name
2NF
Goal: No partial functional dependencies of non-prime attributes (columns that don't exist in any candidate key) on candidate keys.
Solution: I couldn't find any partial functional dependencies.
3NF
Goal: No transitive functional dependencies of non-prime attributes on candidate keys.
Solution: I couldn't find any transitive dependencies.
Problem
Although the tables above seem normalized, there's the following problem: the data in the artist_name column is redundant. An artist with multiple albums will have their name stored multiple times, which we are against.
What am I missing?
i would create a table called artist and in there store the artist id and name and in the album table have a reference to that using a foreign key constraint. So where you would have artist name in album this would change to artist id. It wouldn't be a issue if you just have the name like you do now but if you have additional data that you would need to store for a artist then you would have to create the table anyway which would break the current design as you would have the name in the album table and the rest of the information in the artist table.
The main goal of normalization is to reduce redundancy. With the artist name being in the album table if you ever needed the name of a artist and additional artist info then you would have to include the album table and the artist table which wouldn't make sense and you wouldn't have any other columns besides name to link the tables together or duplicate the data in two places both the album and artist table which would violate the 1st normal form.
Also, with the name being in the album table your data would be split across two tables. The artists name isn't really a dependency on album but on the artist entity. This violates values stored in a column should be of the same domain principle of the 1st normal form.
lets say we have 3 table in our database
tables:
table books:
book_id
book_title
...
table magazines:
magazine_id
magazine_title
...
and genres:
genre_id:
genre_name
and now we say want to know what book has what genre and what magazine has what genre, this is the way i know for two table
relation tables:
table book_genres:
genre_id
book_id
table magazine_genre:
genre_id
magazine_id
in this way we have to create several separate table for joining the books, magazine and maybe more tables. and i been told that always have 2 id column in join tables.
but i'm wondering about if i could do something like this
the table that not working!
table title_genres:
genre_id
book_id
magazine_id
...
this is more simple but i get an error when i insert a book genres that says magazine_id can't be empty NULL because its primary key.
its gonna be save me for creating a lot of tables. like if i decide to have a category table then i have to join books and magazine separately.
and my question: is the 2 column thing is a good practice or there is a better way for this?
You use bridge tables to represent m:n relationships. If a book can have many genres and a magazine can have many genres, then you need bridge tables like the book_genres table you are showing.
And if books are very different from magazines in your database, then yes, have separate tables for books and magazines.
This leads to two bridge tables, just as you describe and I see nothing wrong with this.
Your idea to have one bridge table is generally possible, but doesn't solve any problem.
But well, let's see how we would construct such a multi bridge table. First of all you'll want a check constraint ensuring that always exactly one of the columns book_id and magazine_id is filled. Then you want a unique constraint on COALESCE(book_id, magazine_id), genre_id. This would usually be done with a function index, which MySQL doesn't support as far as I know. I suppose though, that you could create a generated column which you can index in MySQL.
And then you want to read the relations as quick as possible. With a bridge table like book_genres you have one row per book and genre and an index to get the relation as quick as possible. With a multi bridge table like title_genres you don't. You have one table containing relations you are interested in and others you are not interested in. You'd want a partial index like
create unique index idx on title_genres (book_id, genre_id) where book_id is not null;
but MySQL doesn't support partial indexes. You could
create unique index idx on title_genres (book_id, genre_id);
which leads to a larger index, but serves the purpose. You'd do the same with
create unique index idx2 on title_genres (magazine_id, genre_id);
And now, with all this work, what have you gained? Your database has become way more complicated than with the simple book_genres and magazine_genres tables. Keep it simple. Use these two tables instead of the multi bridge monster :-)
You can absolutely store the records this way if you have a category field that has information such as (books, magazines etc). So, in other words your table is vertically partitioned by category field but logically it’s a single table.
Only drawback I can see is if this table grows fast then query performance would be a problem because (a) the table will be huge so it will consume more memory even if you are only looking for specific categories and not all of them (b) you always have to use inline sub query since your category filter have to applied every time for every join and when you use inline queries for joins the database would not be able to make use of indexes will be affect the performance of the queries.
Note : You would not be able to store the records in any other way. For example even if a magazine and a book have same genre you have to have them in separate rows and not the same row because if you do that your model will get into other kind of troubles.
I am using DBDesigner 4 for designing my database relations.
I have a users table and a recipes table. One user can own many recipes but one recipe cannot be owned by many users. This relationship is shown by the user_recipes relation in the picture. (A one-to-many relationship from users to recipes).
However, recipes can be liked by users. Many users can like many recipes. This is a many-to-many relationship between users and recipes and the pivot table for this is users_like_recipes.
But when I create this pivot table, I only need the users_id and recipes_id column. The recipes_users_id column is getting added on its own and I am not able to remove it. It says the third column has come from another Relation which is defined in the model. I guess its the user_recipes relation.
When I remove the user_recipes relation, I get the pivot table like I want to.
But I need the user_recipes relation too!
Please. Any help would be appreciated.
I would suggest removing user_id as a primary key from from the recipes table. Currently the combination if id and user_id provides identification for your recipes table. In this situation multiple user_id's can create the same recipe id because the combination has to be unique. user_id can just be a normal column in your table. If you REALLY want to, you can make an alternate key on (id, user_id) but you do not need it because the id is unique.
I need to make a table 'Movies' which will have columns:
ID Title Description Category etc
And another one called 'Movie_Categories' containing, for example
ID Category
1 Action
2 Adventure
3 Triller
but since category in table Movies will have multiple choices what is the correct way to do this?
should i use comma-separated values like someone said in this post Multiple values in column in MySQL or is there a better way?
This is a many-to-many relationship.
You need a join table to make it right, such as :
CREATE TABLE film_category (
category_id int,
film_id int,
PRIMARY KEY (category_id, film_id)
);
DO NOT GO FOR COMMA-SEPARATED VALUES. NEVER.
Having said that. Bear in mind that when you have a so called many-to-many relationship, that is, a relationship where you can have one category with many movies and one movie with many categories, you will always need to generate an additional table.
This table will only need the Primary Keys of each of the other 2 tables and will have a compound key.
So the schema will end up being:
Movies(ID, Title, Description, Category)
Categories(ID, Category)
Movies_Categories(ID_Movie, ID_Category)
In bold are the primary keys.
In order to get all the categories for a movie you will just have to join each of the three tables.
A final comment about having multi-valued fields is that your table will not be in First Normal Form which will, sooner or later, give you lots of headaches.
The last thing to do is have a non normalized table by storing comma separated values.
*You should have a table movies and a table for categories.
You should create a mapping table which will map the movieId to the categoryId*
I am a beginner with MySQL and so far I have only had to work with 'many to one' table links. I now have a need for a 'many to many' link but am unsure how to do it. As far as I understand I would need a third table.
Basically I have a table full of parks and a table full of links to articles. On the webpage that shows an individual parks details I need a query looking for any attached articles to that park. Usually I would use a park_id column in the other table and link using that but the problem here is each article could be linked to many parks.
Example query would be:
SELECT * FROM tpf_features
Where park_id = 7
But an article may have park_id's of 3, 7, 13, 23.
Can someone point me in the right direction to build this relationship and query up correctly.
Thank you
You should use a third table and associate their id's:
(created the tables only with id's)
Create table parks(
park_id integer,
primary key (park_id)
);
Create table articles(
article_id integer,
primary key (article_id)
);
CREATE TABLE cross_table(
article_id integer,
park_id integer,
Primary Key (article_id,park_id),
Foreign Key (article_id) REFERENCES articles(article_id),
Foreign Key (park_id) REFERENCES parks(park_id)
);
Then when you want to find out information about the articles associated with the parks, you'd do:
SELECT a.*
FROM cross_table c, articles a
WHERE c.article_id = a.article_id
AND c.park_id = 7;
This will return all the information about all the articles related to park_id = 7.
The primary keys, insure that every article has a unique id, every park has a unique id and they only relate once in the cross_table.
Indeed, you will need a third "linking" table that should contain only two columns: park ids in one, and article ids in the other. Although these ids are likely unique primary keys in their respective original tables, they need not be unique in the linking table.
This third linking table allows many occurrences of ids from each original table without conflicting with their uniqueness in those original tables. While each individual id many occur many times in the linking table, each combination of park/article will only occur once.
Then, in order to select all of the articles that relate to park 7, you need only select all of the rows from the linking table where park_id = 7
SELECT * FROM linking_tbl
WHERE park_id = 7