Trouble with JOINS in mysql - 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

Related

Get what areas have more than three qualified employees

I have this tables from the MySql database i'm working with:
create table employees (
num_pass int(5) not null,
name varchar(40),
primary key (num_pass)
)engine=innodb;
create table laboratories (
code int(10) not null,
name varchar(40),
primary key (codi),
)engine=innodb;
create table areas (
code int(5) not null,
codeLab int(10) not null,
level enum('H','M','L'),
primary key (code, codeLab),
foreign key (codeLab) references laboratories(code)
)engine=innodb;
create table qualifieds (
num_pass int(5) not null,
area_assigned int(5),
lab int(5),
primary key (num_pass),
foreign key (num_pass) references employees(num_pass),
foreign key (area_assigned, lab) references areas (code, codeLab)
)engine=innodb;
Now i want to get what areas have more than three qualified employees. Specifically, i want to get area code along with the name of the laboratory, laboratory and ordered by region.
I tried to use this command in order to get the code of the area
select b.code
from employees e, areas b, qualifieds q
where e.num_pass=q.num_pass
and 3 < (select count(b1.code)
from areas b1, qualifieds q1, employers e1
where e1.num_pass=q1.num_pass
and q1.area_assigned=b1.code
and q1.lab=b1.codeLab);
But all what i get is a list of all the area codes repeated as many times as the number of employees (i have areas with code 1,2,3,4 and 6 employees, what i get is the sequence 1,2,3,4 repeated 6 times).Any idea about how to get the information i need?
You can use GROUP BY and HAVING to find a group with more than 3 records...
select areas_assigned, lab, count(num_pass)
from qualifieds
group by areas_assigned, lab
having count(num_pass)>3;
If you then need to expand on this, then add joins...
select q.areas_assigned, l.name, count(q.num_pass)
join laboratories l on l.lab = q.lab
from qualifieds q
group by q.areas_assigned, l.name
having count(q.num_pass)>3;

Create view from 3 different tables?

I'm trying to create a view in MySQL to include from 3 different tables.
CREATE TABLE ACTOR (
ACTOR_ID DECIMAL (2,0) PRIMARY KEY NOT NULL,
ACTOR_FIRST CHAR(25),
ACTOR_LAST CHAR(30),
DOB DATE
);
CREATE TABLE DIRECTOR (
DIRECTOR_ID DECIMAL(2,0) PRIMARY KEY NOT NULL,
DIRECTOR_FIRST CHAR(25),
DIRECTOR_LAST CHAR(30)
);
CREATE TABLE FILM (
FILM_ID DECIMAL(2,0) PRIMARY KEY NOT NULL,
TITLE CHAR(50),
RELEASE_DATE DATE,
DIRECTOR_ID DECIMAL(2,0),
GENRE_ID CHAR(10),
PRODUCTION_ID CHAR(3)
);
The VIEW I'm trying to create:
create view film_production as
select
title,
actor_first,
actor_last,
director_first,
director_last,
Production_id,
release_date
from film,
actor,
director
;
This gives me like 192 results. But I only have 3 actors, with 8 movies with 8 directors, and 6 production_id's. Another thing to note is 1 movie has 2 of the 3 actors in it, so I should have at least 9 movies that show not 192. I don't know what I'm doing wrong. I just cant figure this out. I'm thinking maybe a join or some kind.
Yes, your view should use joins.
BUT, it looks like you are missing a table, something like film_actor.
Using the missing table, and assuming you are trying to get the cast and directors of each movie it would be
SELECT
FILM.*
,ACTOR_FIRST + ' ' + ACTOR_LAST AS actor
,DIRECTOR_FIRST + ' ' + DIRECTOR_LAST AS director
FROM FILM
INNER JOIN FILM_ACTOR fa ON fa.FILM_ID = FILM.FILM_ID
INNER JOIN ACTOR ON ACTOR.ACTOR_ID = FILM_ACTOR.ACTOR_ID
INNER JOIN DIRECTOR d ON d.DIRECTOR_ID = FILM.DIRECTOR_ID
Like I mentioned, you are missing a table that would hold multiple actors and associate them to one movie: a one to many relationship.
Have you thought of adding referential keys between actor and film, and director and film tables?
Actor
CREATE TABLE ACTOR (
ID INT PRIMARY KEY NOT NULL,
FIRSTNAME VARCHAR(25),
LASTNAME VARCHAR(30),
DOB DATE
);
Director
CREATE TABLE DIRECTOR (
ID INT PRIMARY KEY NOT NULL,
FIRSTNAME VARCHAR(25),
LASTNAME VARCHAR(30)
);
Film with connections to actor and director
CREATE TABLE FILM (
FILM_ID INT PRIMARY KEY NOT NULL,
TITLE VARCHAR(50),
RELEASE_DATE DATE,
DIRECTOR_ID INT,
GENRE_ID INT,
PRODUCTION_ID INT,
ACTOR_ID INT,
CONSTRAINT FK_FILM_DIRECTOR_ID FOREIGN KEY (DIRECTOR_ID)
REFERENCES DIRECTOR(ID),
CONSTRAINT FK_FILM_ACTOR_ID FOREIGN KEY (ACTOR_ID)
REFERENCES ACTOR(ID)
);
View combining the 3 tables
create view film_production as
select
title,
a.firstname as actor_firstname,
a.lastname as actor_lastname,
d.firstname as director_firstname,
d.lastname as directory_lastname,
Production_id,
release_date
from film f
left join actor a on f.actor_id = a.id
left join director d on f.director_id = d.id;
Example: http://sqlfiddle.com/#!9/9fe1e
Note that I have used INT instead of DECIMAL for ID fields and VARCHAR instead of CHAR fields. This may help in allocating the right space for most general purpose uses.

Joining 2 tables, need to display all fields based on highest price, with no duplicates from a different field

I need to show all fields on the most expensive car of each manufacturer.
The two tables being used are:
CREATE TABLE CARS
(
Vehicle_Identification_Number int(10) NOT NULL UNIQUE,
Manufacturers_ID int(5),
Owner_ID int(10),
Model varchar(25),
Manufaturer_Year int(4),
Mileage int(10),
Price int(10),
PRIMARY KEY (Vehicle_Identification_Number),
FOREIGN KEY (Manufacturers_ID) REFERENCES MANUFACTURERS (Manufacturers_ID),
FOREIGN KEY (Owner_ID) REFERENCES OWNERS (Owner_ID)
)
ENGINE= innodb;
CREATE TABLE MANUFACTURERS
(
Manufacturers_ID int(5) UNIQUE,
Name varchar(15) UNIQUE,
City varchar(30),
State char(2),
Zip char(5),
Phone char(10),
PRIMARY KEY (Manufacturers_ID)
)
ENGINE= innodb;
What I have working so far is:
SELECT *
FROM MANUFACTURERS
LEFT JOIN CARS
ON MANUFACTURERS.Manufacturers_ID = CARS.Manufacturers_ID
UNION
SELECT *
FROM MANUFACTURERS
RIGHT JOIN CARS
ON MANUFACTURERS.Manufacturers_ID = CARS.Manufacturers_ID
ORDER BY Price DESC;
Here is where I am stuck, everything I have tried left me with an error message. Any help would be appreciated.
I'm not sure what you mean by "no duplicates from a different field".
The highest price for each manufacturer is this set. (There might be more than one car at the highest price.)
select Manufacturers_ID, max(Price)
from cars
group by Manufacturers_ID;
Join on both columns in that set. (Second inner join, below.)
select MANUFACTURERS.*, CARS.*
from CARS
inner join MANUFACTURERS
on MANUFACTURERS.Manufacturers_ID = CARS.Manufacturers_ID
inner join (select Manufacturers_ID, max(Price) as Price
from cars
group by Manufacturers_ID) as MOST_EXPENSIVE
on CARS.Manufacturers_ID = MOST_EXPENSIVE.Manufacturers_ID
and CARS.Price = MOST_EXPENSIVE.Price;

SQL select entries in other table linked by foreign keys

I have redesigned my database structure to use PRIMARY and FOREIGN KEYs to link the entries in my 3 tables together, and I am having problems trying to write queries to select data in one table given data in a another table. Here is an example of my 3 CREATE TABLE statements:
CREATE TABLE IF NOT EXISTS players (
id INT(10) NOT NULL AUTO_INCREMENT,
username VARCHAR(16) NOT NULL,
uuid VARCHAR(200) NOT NULL DEFAULT 0,
joined TIMESTAMP DEFAULT 0,
last_seen TIMESTAMP DEFAULT 0,
PRIMARY KEY (id)
);
/* ^
One |
To
| One
v
*/
CREATE TABLE IF NOT EXISTS accounts (
id INT(10) NOT NULL AUTO_INCREMENT,
account_id INT(10) NOT NULL,
pass_hash VARCHAR(200) NOT NULL,
pass_salt VARCHAR(200) NOT NULL,
created BIGINT DEFAULT 0,
last_log_on BIGINT DEFAULT 0,
PRIMARY KEY (id),
FOREIGN KEY (account_id) REFERENCES players(id) ON DELETE CASCADE
) ENGINE=InnoDB;
/* ^
One |
To
| Many
v
*/
CREATE TABLE IF NOT EXISTS purchases (
id INT(10) NOT NULL AUTO_INCREMENT,
account_id INT(10) NOT NULL,
status VARCHAR(20) NOT NULL,
item INT NOT NULL,
price DOUBLE DEFAULT 0,
description VARCHAR(200) NOT NULL,
buyer_name VARCHAR(200) NOT NULL,
buyer_email VARCHAR(200) NOT NULL,
transaction_id VARCHAR(200) NOT NULL,
payment_type VARCHAR(20) NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (account_id) REFERENCES accounts(account_id) ON DELETE CASCADE
) ENGINE=InnoDB;
Say for example, I want to select all the usernames of users who purchased anything greater than $30. All the usernames are stored in the players table, which is linked to the accounts table and that is linked to the purchases table. Is this this the best way to design this relational database? If so, how would I run queries similar to the above example?
I was able to get get all of a users purchase history given their username, but I did it with 2 sub-queries... Getting that data should be easier than that!
Here is the SELECT query I ran to get all of a players purchase data:
SELECT *
FROM purchases
WHERE account_id = (SELECT id FROM accounts WHERE account_id = (SELECT id FROM players WHERE username = 'username'));
Also, when I try to make references to the other tables using something like 'players.username', I get an error saying that the column doesn't exist...
I appreciate any help! Thanks!
Your design is ok in my opinion. The relation between players and account is one-to-many and not one-to-one since this way, you can have two tuples referencing a single player.
I would write the query you need as:
SELECT DISTINCT p.id, p.username
FROM players p INNER JOIN accounts a ON (p.id = a.account_id)
INNER JOIN purchases pc ON (a.id = pc.account_id)
WHERE (pc.price > 30);
As Sam suggested, I added DISTINCT to avoid repeating id and username in case a user have multiple purchases.
Note the id is here to avoid confusion among repeated usernames.

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;