denormalize many to many relationship in MySQL - mysql

I would like to denormalize many to many relationship in mysql. In order to import to MongoDB as Json format Schema.
Input
I have 3 tables:
Movies : id, title, url
Genres : id, genre
movie_genres : movie_id, genre_id
example
movie Table
id title link
1 star wars http://link-to-imdb
2 shrek http://link-to-imdb
movie_genres Table
movie genre
1 1
2 1
genres Table
id genre
0 unknown
1 action
2 comedy
3 drama
I would like to transform it to a single table by moving genres into movies as array or multiple values.
There are quite a few limited number of genres (only 15).
Output
So, Final output of table would be:
Movies : id, title, url, genre
Here, genre would be multiple values.
Example:
id title link genre
1 star wars http://link-to-imdb action, drama, sci-fi
2 shrek http://link-to-imdb anime
I did this - MySQL Query:
select M.id ,M.title ,M.release_date, M.video, M.IMDBURL, G.genre
from genres G, movie_genres MG, movies M
where M.id = MG.movie and MG.genre = G.id
but causes lot of repetition depending on number of genres. It would be nice If I could dump genres altogether.

In this cause you should use GROUP_CONCAT() function
SELECT movie.id, movie.title, movie.url, GROUP_CONCAT(g.genre SEPARATOR ', ') AS genres
FROM movie
LEFT JOIN movie_genres mg ON movie.id = mg.movie_id
LEFT JOIN genres g ON mg.genre_id = g.id
GROUP BY movie.id
I didn't test the query above (there could be some typos), but I hope you will be able to get the idea

Related

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.

organize similar items in columns from same table

I've a table named 'artist' with columns - id, name, genre
I need to find out all artist that share the same genre.
Here's an example: If artist X has genre ‘rock’ and ‘classic’, artist Y has genre ‘classic’ and ‘pop’, and artist Z has genre ‘pop’, then sample output as below:
first artist | second artist | genre
X | Y | Classic
Y | Z | Pop
Join data using Genre
Exclude "mirror duplicates" (XY-Classic vs YX-Classic) and loops (
ZZ-Pop ) using S.id < J.id condition:
Select S.Name as FirstArtist,
J.Name as SecondArtist,
S.Genre as CommonGenre
From Artist S
Inner Join Artist J
ON S.Genre = J.Genre and S.id < J.id
Judging from your sample output, you're trying to do two things. First, order your data set, and second, "pivot" it so some columns in your data become rows.
The first part:
SELECT name, genre
FROM artist
ORDER BY genre
The second part is presentation. There are many ways to do this. You could try this, for example.
SELECT GROUP_CONCAT(name ORDER BY name) AS names,
genre
FROM artist
GROUP BY genre
ORDER BY genre
Or you could look up various techniques in MySQL to do pivoting. Hint: they're all kind of difficult.
Or, you could do this in your presentation software.

key with multiple foreign keys

I have a database MOVIES and it has 2 tables. 1 is MOVIE and the other is GENRE.
I want to be able to have row entry of MOVIE to be associated with multiple rows in the GENRE table. Can this be done with only 1 column in the MOVIE table?
I have seen examples of movie databases, but they only allow 1 genre to be mapped to a single movie. Is there a way to have multiple genres belonging to a single entry movie? I'm using mySQL to create the database.
You should have a third table, MOVIE_GENRE that implements this many-to-many relationship. It has foreign keys into both the MOVIE and GENRE tables. A query to find list all the movies with their genres would look like:
SELECT m.title,
IFNULL(GROUP_CONCAT(g.name), "") genres
FROM Movie m
LEFT JOIN Movie_Genre mg ON m.id = mg.movie_id
JOIN Genre g ON g.id = mg.genre_id
GROUP BY m.id
You need a many-to-many or join table with 2 colums,
MovieID and GenreID
Having this structure will allow you to link a single movie to as many genres as you like

Need MySQL Query ManyToMany Mapping Count Records

i have 3 tables (ManyToMany):
movie
moviegenre
genre
Structure of my tables:
movie:
id
name
...
genre:
id
name
moviegenre:
idMovie
idGenre
Movie is connected with genre via the moviegenre table (ManyToMany connection).
Now id like to know how many movies i have for genre (for example "Action")
Example result:<br/>
Action | 12<br/>
Horror | 9<br/>
Thriller| 3<br/>
...
Could you please help me creating this "simple" query? (MySQL 5.5.13)
Thank you very much! :D
SELECT G.name, count(MG.idMovie)
FROM MovieGenre MG
INNER JOIN Genre G on MG.idGenre = G.ID
GROUP BY G.name

What is the most efficient way to search rows in a table based on metadata stored in another table?

Consider these two tables stored in a MySQL database. The first stores a list of movies and the second stores metadata about each movie. Rather than adding 'category' and 'actor' fields to the movies table, they are stored as key/value pairs in the movie_attributes table, as each movie may have more than one category or actor attributed to it.
movies
id name
-----------
0 hot rod
1 star wars
movie_attributes
id movie_id key value
----------------------------------------
0 0 genre comedy
1 0 genre stupid
2 0 actor andy samberg
3 0 actor harrison ford
4 0 actor chester tam
5 1 genre adventure
6 1 actor harrison ford
What would be the most efficient way to query the movies based on a search criteria that allows the user to select multiple genres and multiple actors? If the user adds more than one category to their search, I would like the results to include movies from both categories (but only those videos that also match the actors selected.)
For example, this pseudo-query:
select * from movies where (genre = 'comedy' OR genre = 'adventure') AND (actor = 'harrison ford')
would return this:
id name
-----------
0 hot rod
1 star wars
Currently, my solution uses a mess of subqueries and it's awfuly slow, as my database contains more than two attribute key types per movie (genres, actors, actresses, tags, etc..) and it's terribly slow. Here's the real query that's equivalent to the example pseudo-query above:
select * from movies
WHERE (select count(*) from movie_attributes
WHERE key='genre'
AND (value='comedy'
OR value='adventure'))>0
AND
(select count(*) from movie_attributes
WHERE key='actor'
AND (value='harrison ford'))>0
Is there a more efficient way to achieve the same results using joins or some other SQL voodoo magic I'm unfamiliar with? Thanks!
SELECT *
FROM movies
WHERE EXISTS(
SELECT NULL
FROM movie_attributes
WHERE movies.id = movie_attributes.movie_id AND
key = 'genre' AND value in ('comedy', 'adventure')
) AND
EXISTS(
SELECT NULL
FROM movie_attributes
WHERE movies.id = movie_attributes.movie_id AND
key = 'actor' AND value = 'harrison ford'
)
I would however suggest against this kind of design, see #n8wrl answer.
See if this one helps:
SELECT m.* FROM `movie_attributes` ma
JOIN `movies` m ON (ma.movie_id=m.id)
WHERE
(`key` = 'genre' and `value` in ('comedy', 'adventure'))
OR (`key` = 'actor' and `value` in ('harrison ford'))
Secondly, make sure, there is an index on the fields key, value in movie_attributes