N:N Relation Mysql [duplicate] - mysql

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
problem in many to many relationship
I have a table of movies and a table of categories. I would like to register one more category for a film. And a category for several films. That is, a relation N: N. How do I do that in php and Mysql?
For example:
Categorie 1 -> Movie 1
and Movie 2
Movie 2 -> Categorie 1
and Categorie 2

For a many to many relationship, you need a third table called the junction table
So it would look like that
Movie
id | desc
Category
id | desc
MoviesCategories
id | movieID | categoryId
Your selects would be on MoviesCategories and would look like this
SELECT *
FROM
MoviesCategories INNER JOIN Category ON MoviesCategories.CategoryId = Category.Id
INNER JOIN movie ON MoviesCategories.MovieID = Movie.ID

You need a table for that relationship. Like this:
MovieToCategory
ID
CategoryID
MovieID
Alternatively you can create a composite primary index only allowing each movie to category combination one time:
MovieToCategory
CategoryID
MovieID

Related

How to find all children from another table?

I have two tables
CATEGORY
id category parent_id
1 Electronic
2 Furniture
3 Phone 1
4 LCD 1
5 Watch 1
6 Desk 2
ORDER
id customer product category_id
1 John Smartphone 3
2 Marry Montior 4
3 King Wood-Desk 6
I want to find all of electronic result by child_id.
Like this..
SELECT product FROM order WHERE category_id = (category.id = 1)
RESULT
product
Smartphone
Monitor
Is there any expression like this in MySQL?
You can use a join for this. You also will need to encapsulate the order table name with backticks because order is reserved (alternatively you could rename that table to save yourself from encapsulating everytime).
SELECT product FROM `order` as o
join category as c
on o.category_id = c.id
WHERE c.parent_id = 1
The on tells the DB what to data to join on. The as creates an alias so the full table name doesn't need to be written out everytime. (The as also is optional, I find it easier to read, FROM `order` o would be the same)
An alternative approach could be using a sub-query:
SELECT product
FROM `order`
WHERE category_id in (SELECT id FROM CATEGORY where parent_id = 1)
You have to use INNER JOIN
SELECT order.product
FROM order
INNER JOIN category
ON order.category_id = category.id
WHERE category.parent_id = 1
The ON keyword shows what columns will be compare between these tables. When you make a JOIN you need to put the table name before the column name separated with "." because it is possible to exist a column with the same name in both tables.

SQL column with multiple values

i want to know how can we store multiple values in a sql column, or which is the best way to store the values in a sql column.
Consider in a movie table, a movie will be having multiple Genre
eg,
Genre: "Action, Adventure, Fantasy"
Genre: "Adventure, Drama, Fantasy, Thriller"
which is the best way to store the Genre values in database.
This is a classic n to m relation. It works like this
movies table
------------
id
name
...
genres table
------------
id
name
movie_genres table
------------------
movie_id
genre_id
The movie_genres table then contains one record for each genre of a movie. Example:
movie_genres
------------
movie_id | genre_id
1 | 1
1 | 2
1 | 13
To get the genres of a movie do:
select g.name as genre_name
from genres g
join movie_genres mg on mg.genre_id = g.id
join movies m on m.id = mg.movie_id
where m.name = 'star wars'
IMO, using a n:m relationship, as juergen_d suggested, is the best option.
But in mysql there is another option it might work in your case: using SET data type. Details here. Defintely not as powerful nor robust as using n:m relationship. Not normalization friendly.

How is JOIN working, how can i use it correctly, do I even need it?

These are my tables:
category (id(PK), name (varchar))
book_category (book_id(FK PK), category_id(FK PK)
book (id(PK), name(varchar))
Now I want to create a query where I can get every book from one category
I'm stuck here, I cant figure out how I can get data from more then one table, I tried a lot with INNER JOIN but get SQL errors all the time
for example:
SELECT * FROM book
INNER JOIN category
ON category.id = book.id
So my question is how can I use the book_category table?
What you have here is an intermediate table which allows you to have a many to many relationship. If you don't have the second table you couldn't have more than one book belonging to one category whilst also having the ability for more than one category to belong to one book.
E. G.
You have book 1, book 2, book 3 and category 1, category 2, category 3.
If a book can only belong to one category then you just have a foreign key in book which links to the primary key in category. E. G. Book 1 and book 2 belong to category 2.
But what if book 1 belongs to both category 2 and category 3? You can't have this relationship with just the 2 main tables because there's only 1 foreign key field.
Your second table now links the two main tables so your book table has a foreign key to a book id in the intermediate table and your category table has a foreign key to a category id in the intermediate table.
Now you can have these entries in the intermediate table.
1. Book 1 linked to category 2
2. Book 1 linked to category 3
3. Book 2 linked to category 2
Joining all three tables together will tell you that book 1 belongs to both category 2 and 3 and that book 2 belongs to category 2.
EDIT: adding an example to illustrate the point.
Book Table:
id name
1 A Best Seller
2 A Worst Seller
3 A Funny Horror
Category Table:
id name
1 Horror
2 Comedy
3 Non Fiction
Book-Category Table
book_id category_id
1 1
2 3
3 1
3 2
This structure says that book 1 belongs to the category Horror, book 2 belongs to Non Fiction and book 3 belongs to both Horror and Comedy.
The query, to find all books belonging to the Horror category is:
select book.name from
books join book_category on book.id = book_category.book_id
where book_category.category_id = 1
This finds every book name where the intermediate table has an entry for that book, belonging to the category with an id of 1.
You don't really need to join to the Category table at all unless
(a) you don't know the id of the category you are searching for (and thus need to search by category name, which wouldn't be recommended), or
(b) you want to include in the query some information about the category (such as its name, which might be important if you aren't limiting your query to a single Category)
Hope this helps.
Add categoryid into book table as a FK.
So your query will be like
select b.* from book as b inner join
category as c on b.categoryid=c.categoryid
and b.categoryid=#yourValue
Make changes in the table structure:
category : (id(PK), name (varchar))
book : (id(PK), name(varchar), categoryid(int)) // categoryid is FK of category table
Then use query:
SELECT b.*
FROM book AS b
INNER JOIN category AS c ON b.categoryid=c.id
Well, you need to use different JOIN:
SELECT b.* FROM book b
INNER JOIN book_category bc ON bc.book_id = b.id
WHERE bc.category_id = {DESIRED_VALUE}

JOIN 2 tables with where condition, but show first row from table2

I have 2 tables. One is movie table, where all movie data is stored and another one is relation table, where I can see which movie is attached to which category. If I want to show movies from category 6 I join them like this:
SELECT t1.title, t2.category FROM movies t1
JOIN movie_categories t2 ON t1.movieid = t2.movieid
WHERE t2.category = 6
And it works just fine. However, movie SEF url are generated based on the first row from table2 (actually it should connect to table3, a category table, where i will find sef alias name, but for now I dont need that, I just want to know how to get first category). So lets say, movie have 3 categories, which will be looking like this:
Table 2 [relations table]
id movieid category
1 1 3
2 1 6
3 1 2
Table 1 [movie table]
movieid
1
2
The query I showed before returns results like this:
title category
bla1 6
bla2 6
However to create sef url, I need to get the first category id from relations table which is 3 in this case.
I'd like to know how to construct query to achieve the result I described.
ASSUMPTION: by MIN you mean the lowest ID in movie_Categories and then display it's category value.
Generate a set of data which is the lowest ID for each movie (subquery)
Join it back to the movie list
Then join your movie categories back to the generated set with the min value
Join the movie categories again back to the base movie set to get the limiting set for category.
Then limit the data base the category desired.
.
drop table movie;
drop table movie_categories;
create table movie (movieid int, Title varchar(10));
create table movie_categories (Id int, movieID int, category int);
insert into movie values (1, 'The');
insert into movie values (2, 'End');
insert into movie_categories values (1,1,3);
insert into movie_categories values (2,1,6);
insert into movie_categories values (3,1,2);
--To aid in understanding you may want to select * and see why this works and remove the where clause.
--Basically the two joins to Movie_Categories is once for the LOWEST ID and once again to get the limiting category.
SELECT M.Title, MC1.Category
FROM Movie M
INNER JOIN (SELECT min(ID) ID, MovieID
from movie_categories mc
GROUP BY MovieID) L
on L.MovieID = M.MovieID
INNER JOIN Movie_Categories MC1
on L.MovieID = MC1.MovieID
INNER JOIN Movie_Categories MC2
on l.movieid = mc2.movieid
and L.ID = MC1.ID
where mc2.category = 6
Results in:
title category
The 3
Note: the 2nd title isn't listed because there are no records in movie_category which match a category of 6.

How to select records in a many-to-many relation using an AND condition [duplicate]

This question already has answers here:
How to return rows that have the same column values in MySql
(3 answers)
Closed 8 years ago.
I have a DB that tracks movies and actors, with the following tables:
Person(ID, Name)
Movie(ID, Name)
Actors(ID, PersonID, MovieID)
ID fields are all primary keys and PersonID & MovieID are foreign keys.
I want to select all the movies that Tom Cruise and Brad Pitt played in.
I tried to do the following:
SELECT * FROM Person, Actors
WHERE Person.ID = Actors.ActorID AND
(Person.Name= 'Tom Cruise' or Person.Name= 'Brad Pitt')
GROUP BY Actors.MovieID
HAVING COUNT(Actors.MovieID) > 1
This doesn't work, because the person name is not unique (and I can't change it to unique). If I have another actor named Brad Pitt and the two Brad Pitts played in the same movie it would return as a result too.
How can I do it?
NOTE: The number of actors I am querying about can change. I might need a movie with 10 actors that all played in it.
Do a inner join between the tables as below
SELECT m.Name as MovieName
FROM Movie m
inner join Actors a
on m.ID = a.MovieID
inner join Person p
on p.ID = a.ActorID
and p.Name in ('Tom Cruise','Brad Pitt')