I am trying to link 4 tables together with INNER JOIN - mysql

My code looks like this
CREATE TABLE Genre (
genreID INT NOT NULL DEFAULT 0,
genreName VARCHAR(20) NULL,
PRIMARY KEY (genreID));
CREATE TABLE Artists (
ArtistID INT NOT NULL DEFAULT 0,
name VARCHAR(45) NULL,
Genre_genreID INT NOT NULL,
PRIMARY KEY (ArtistID),
FOREIGN KEY (Genre_genreID)
REFERENCES Genre(genreID));
CREATE TABLE Albums (
albumsID INT NOT NULL DEFAULT 0,
name VARCHAR(45) NULL,
Artists_ArtistID INT NOT NULL,
PRIMARY KEY (albumsID),
FOREIGN KEY (Artists_ArtistID)
REFERENCES Artists(ArtistID));
CREATE TABLE Songs (
songID INT NOT NULL,
name VARCHAR(45) NULL,
length TIME NULL,
Albums_albumsID INT NOT NULL DEFAULT 0,
PRIMARY KEY (songID),
FOREIGN KEY (Albums_albumsID)
REFERENCES Albums (albumsID));
SELECT Artists.name, Genre.genreName, Songs.name
FROM Songs
INNER JOIN Genre ON Artists.ArtistID=Genre.genreID
INNER JOIN Artists ON Albums.Artists_ArtistID=Artists.ArtistID
INNER JOIN Albums ON Songs.Albums_albumID=Albums.albumsID;
Looking to try and get the name of the artists, genre and song to all match up and display. Yet I get
Unknown column 'Artists.ArtistID' in 'on clause'
Im fairy new to SQL and to INNER JOINS any help and explanations would be great!

Try this
SELECT Artists.name, Genre.genreName, Songs.name
FROM Songs
INNER JOIN Albums ON Songs.Albums_albumID=Albums.albumsID
INNER JOIN Artists ON Albums.Artists_ArtistID=Artists.ArtistID
INNER JOIN Genre ON Artists.ArtistID=Genre.genreID;
check the sequence and occurrence of tables in join

you are mention the Songs table in first row joining. but your joining the table of ON function in last line only like your code, you should try this method:
SELECT
Artists.name, Genre.genreName, Songs.name
FROM Songs
INNER JOIN Albums
ON Songs.Albums_albumID=Albums.albumsID
INNER JOIN Artists
ON Albums.Artists_ArtistID=Artists.ArtistID
INNER JOIN Genre
ON Artists.ArtistID=Genre.genreID;

Related

Mysql Selecting the average value of a column from things that are stored in 3 tables

I am fairly new with databases and I am starting with mysql.
I have 4 tables (movie, genre, movieGenre and movieRating):
movie:
CREATE TABLE `movie` (
`movieId` INT NOT NULL,
`title` VARCHAR(155) NOT NULL,
PRIMARY KEY (`movieId`)
);
genre
CREATE TABLE `genre` (
`code` INT NOT NULL AUTO_INCREMENT,
`genre` VARCHAR(20) NOT NULL,
PRIMARY KEY (`code`)
);
movieGenre
CREATE TABLE `movieGenre` (
`movieId` INT,
`genreId` INT,
CONSTRAINT `fk_movieGenre_movie` FOREIGN KEY (`movieId`) REFERENCES `movie`(`movieId`),
CONSTRAINT `fk_movieGenre_genre` FOREIGN KEY (`genreId`) references `genre`(`code`)
);
and movieRating
CREATE TABLE `movieRating` (
`userId` INT NOT NULL AUTO_INCREMENT,
`movieId` INT NOT NULL,
`rating` FLOAT NOT NULL,
`date` DATE,
CONSTRAINT `fk_movieRating_user` FOREIGN KEY (`userId`) REFERENCES `user`(`userId`),
CONSTRAINT `fk_movieRating_movie` FOREIGN KEY (`movieId`) REFERENCES `movie`(`movieId`)
);
I need to find the average rate for each movie genre, sorted in descended average rating value and if a genre does not have any associated rating, it should be reported with 0 ratings value
I am lost. I don't know how to achieve this result. Could you please help me?
I have figured out how to find the avg rate for each movie but I don't know how to change this so I find for each genre:
SELECT `movie`.`movieId`, AVG(`movieRating`.`rating`) FROM `movie`
INNER JOIN `movieRating` ON `movie`.`movieId` = `movieRating`.`movieId`
GROUP BY `movieRating`.`movieId`
ORDER BY AVG(`movieRating`.`rating`) DESC;
Well, I have put an ID in your genre table, otherwise I can't make this work. So, it has become:
CREATE TABLE `genre` (
`genreId` INT,
`code` INT NOT NULL AUTO_INCREMENT,
`genre` VARCHAR(20) NOT NULL,
PRIMARY KEY (`code`)
);
And I have to make the assumption that all the genres are defined in this table. I'll take this table as a base, and, as you suggested use a subquery:
SELECT
genre.code,
genre.genre,
(<my sub select comes here>)
FROM
genre;
This basically gets you a list of all genres. Now it is up to the subquery to give the average rate for the movies in each genre. That subquery could look something like this:
SELECT AVG(movieRating.rating)
FROM movieRating
JOIN movie ON movie.movieId = movieRating.movieId
JOIN movieGenre ON movieGenre.movieId = M.movieId
WHERE movieGenre.genreId = genre.genreId;
I kept it very simple. We start with the average we want, from movieRating, and work through the movie and movieGenre tables to get to the genreId in that last table. Notice the genre.genreId which comes from the main query. We are implicitly grouping by genreId.
Now you can put this subselect in the main query, but that still doesn't solve the situation in which there is not rating to take an average from. It would result in NULL, meaning: no result. That is almost good enough, but you could put a IFNULL() around it to get a proper zero result.
The total query would then become this:
SELECT
genre.code,
genre.genre,
IFNULL((SELECT AVG(movieRating.rating)
FROM movieRating
JOIN movie ON movie.movieId = movieRating.movieId
JOIN movieGenre ON movieGenre.movieId = M.movieId
WHERE movieGenre.genreId = genre.genreId), 0) AS Average
FROM
genre;
I can't guarantee this will work since I cannot test it, and testing is everything when writing queries.
You should left join all tables and then group by gerne
SELECT `genre`,AVG(IFNULL(`rating`,0)) avgrate
FROM `movie` m
LEFT JOIN `movieRating` mr ON m.`movieId` = mr.`movieId`
LEFT JOIN movieGenre mg ON mg.`movieId` = m.`movieId`
LEFT JOIN `genre` g ON g.`code` = mg.`genreId`
GROUP BY `genre`
I general produce data for your tables, and then start by joing the tables, and see f you get the result you want, if not change the joins to LET Join one by one till you get the result you want, of course you need ro calculate teh avg from 3 or 4 movies

Trouble with JOINS in mysql

I was working in mySQL and made a fake database for reviews, reviewers and tv series. So I made 3 different tables, one for reviewers, one for reviews and one for the series.
CREATE TABLE reviewers
(
id INT AUTO_INCREMENT PRIMARY KEY,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(150) NOT NULL
);
CREATE TABLE series
(
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(100) NOT NULL,
released_year YEAR(4),
genre VARCHAR(50)
);
CREATE TABLE reviews(
id INT AUTO_INCREMENT PRIMARY KEY,
rating DECIMAL(2,1),
series_id INT,
reviewer_id INT,
FOREIGN KEY(series_id) REFERENCES series(id),
FOREIGN KEY(reviewer_id) REFERENCES reviewers(id)
);
The thing that I wanted to ask is, how can I get the highest rating from each reviewer and in which show they gave it?
UPDATE
I came up with this code
SELECT first_name,last_name,title, a.series_id,a.rating FROM
( SELECT series_id,MAX(rating) AS max FROM reviews
GROUP BY series_id ) AS b
INNER JOIN reviews AS a
ON a.series_id=b.series_id AND a.rating=b.max
INNER JOIN reviewers
ON reviewers.id=a.reviewer_id
INNER JOIN series
ON series.id=a.series_id
GROUP BY series_id;
which gives me the max rating in each series and who gave that rating

MySQL group duplicate ID without loosing other data

I'm trying to make a cookbook and I'm having an issue with duplication. It will be easier to understand with an example, so let's begin:
My tables look like this:
create table Recipe (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(25),
description VARCHAR(50),
instructions VARCHAR(500))
ENGINE=InnoDB DEFAULT CHARSET=utf8;
create table Ingredient (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50))
ENGINE=InnoDB DEFAULT CHARSET=utf8;
create table Measure (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(30))
ENGINE=InnoDB DEFAULT CHARSET=utf8;
create table RecipeIngredient (
recipe_id INT NOT NULL,
ingredient_id INT NOT NULL,
measure_id INT,
amount INT,
CONSTRAINT fk_recipe FOREIGN KEY(recipe_id) REFERENCES Recipe(id),
CONSTRAINT fk_ingredient FOREIGN KEY(ingredient_id) REFERENCES Ingredient(id),
CONSTRAINT fk_measure FOREIGN KEY(measure_id) REFERENCES Measure(id))
ENGINE=InnoDB DEFAULT CHARSET=utf8;
and when I run a query that looks like this:
SELECT r.name AS 'Recipe',
r.instructions,
ri.amount AS 'Amount',
mu.name AS 'Unit of Measure',
i.name AS 'Ingredient'
FROM Recipe r
JOIN RecipeIngredient ri on r.id = ri.recipe_id
JOIN Ingredient i on i.id = ri.ingredient_id
LEFT OUTER JOIN Measure mu on mu.id = measure_id;
I'm getting this result :
The problem is that Chocolate Cake is duplicating even though it's the same recipe it just has more than one ingredient. Could you please help me solve this problem, so I would get one instance of Recipe?
Use GROUP_CONCAT to combine values from multiple rows in a group into a comma-separated list. And use CONCAT to concatenate strings, like concatenating the amount to the unit and ingredient.
SELECT r.name, r.instructions,
GROUP_CONCAT(CONCAT(ri.amount, mu.name, ' ', i.name)) AS ingredients
FROM Recipe r
JOIN RecipeIngredient ri on r.id = ri.recipe_id
JOIN Ingredient i on i.id = ri.ingredient_id
LEFT OUTER JOIN Measure mu on mu.id = measure_id
GROUP BY r.id;

Join table on already joined table

I'm struggling to put together a select statement that joins 3 tables.
Here's the database:
CREATE TABLE Beerstyles
(
style_id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
style_name VARCHAR(50) NOT NULL
)ENGINE=InnoDB;
CREATE TABLE Breweries
(
brew_id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
booth_num VARCHAR(10) NOT NULL,
brew_name VARCHAR(50) NOT NULL
)ENGINE=InnoDB;
CREATE TABLE Beers
(
beer_id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
beer_name VARCHAR(50) NOT NULL,
alc_vol DECIMAL(2,1) NOT NULL,
fk_style_id INT NOT NULL,
fk_brew_id INT NOT NULL
)ENGINE=InnoDB;
CREATE TABLE Favorites
(
fav_id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
user_id VARCHAR(55) NOT NULL,
fk_beer_id INT NOT NULL,
fav_comment VARCHAR(255)
)ENGINE=InnoDB;
ALTER TABLE Beers ADD CONSTRAINT FK_BeerStyle_Style FOREIGN KEY (fk_style_id) REFERENCES Beerstyles (style_id);
ALTER TABLE Beers ADD CONSTRAINT FK_BeerBrew_Brew FOREIGN KEY (fk_brew_id) REFERENCES Breweries (brew_id);
ALTER TABLE Favorites ADD CONSTRAINT FK_FavBeer_Beer FOREIGN KEY (fk_beer_id) REFERENCES Beers (beer_id);
And here's the first part:
SELECT * FROM Favorites JOIN Beers ON Favorites.fk_beer_id = Beers.beer_id
I need to mix in the brew_name, but haven't been able to get it right. When I try to join Breweries (ON Favorites.fk_brew_id = Breweries.brew_id) i get an error saying "Unknown column 'Favorites.fk_brew_id' in 'on clause'"
Hope you guys can help me out :)
There is no fk_brew_id in the Favorite table, but you have to add the JOIN condition to the Beers table not to the Favorite table like this:
SELECT
bw.brew_name,
b.beer_name,
f.fav_comment,
...
FROM Favorites AS f
INNER JOIN Beers AS b ON f.fk_beer_id = b.beer_id
INNER JOIN Breweries AS bw ON b.fk_brew_id = bw.brew_id;
SELECT *
FROM Favorites
JOIN Beers
ON Favorites.fk_beer_id = Beers.beer_id
JOIN Breweries
ON Beers.fk_brew_id = Breweries.brew_id
Of course is real life you shoudl never use select *. When you have a join you are repeating columns and causing your query to be slower.

Select only the last inserted item related to another registry

I modeled a small database for easier explanation:
CREATE TABLE bands (
id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(120) NULL,
PRIMARY KEY(id)
)
TYPE=InnoDB;
CREATE TABLE albums (
id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
band_id INTEGER UNSIGNED NOT NULL,
album_name VARCHAR(120) NULL,
rating INTEGER UNSIGNED NULL,
insertion_date TIMESTAMP NULL,
PRIMARY KEY(id),
INDEX albums_FKIndex1(band_id),
FOREIGN KEY(band_id)
REFERENCES bands(id)
ON DELETE NO ACTION
ON UPDATE NO ACTION
)
TYPE=InnoDB;
Now, pretending that we already have some bands and many albums registered in their respective tables, I want to select ONLY the last inserted album from each registered band.
PS: I have to use the "album.insertion_date" field to determine which album is the last inserted.
Try joining the two tables and filtering by insertion_date and band:
SELECT al.*
FROM albums al
INNER JOIN bands b ON al.band_id=b.id
WHERE al.insertion_date=(
SELECT max(insertion_date)
FROM albums
WHERE band_id=b.id
)
Try this one:
select b.name, a.album_name, a.isertion_date
from bands b, albums a
where a.band_id = b.id
and a.insertion_date = (select max(a1.insertion_date) from albums a1 where a1.band_id = b.id)
Considering that you have the albums' ids to be AUTO_INCREMENT and the possibility for the insertion_date to be NULL(as it is the default value), using insertion_date to determine the results is not the smartest thing to do but ... there you go:
SELECT DISTINCT band, last_album, insertion_date
FROM (
SELECT bands.name AS band, albums.album_name AS last_album, albums.insertion_date
FROM bands
JOIN albums ON bands.id=albums.band_id
ORDER BY albums.insertion_date DESC
) t1
GROUP BY band;