Get tickets available with their price - mysql

I'm tyring to get this query, but I think all the joins and sub queries are getting me confused, and it uses every table in my database.
CREATE TABLE Zone(
name char(12) not null,
price_multiplier float not null default 1.0,
primary key (name)
);
CREATE TABLE Seat(
row_no char(3) not null,
zone_name char(12) not null,
primary key (row_no),
foreign key (zone_name)
references Zone(name)
);
CREATE TABLE Production(
title varchar(100) not null,
url varchar(30) not null unique,
base_price numeric(5,2) not null,
mins smallint default 90,
genre varchar(30),
description text,
primary key (title)
);
CREATE TABLE Performance(
id mediumint not null AUTO_INCREMENT,
date_time datetime not null unique,
title varchar(100) not null,
primary key (id),
foreign key (title)
references Production(title)
);
CREATE TABLE Booking(
ticket_no mediumint not null AUTO_INCREMENT,
row_no char(3) not null,
performance_id mediumint not null,
customer_name varchar(300) not null,
primary key (ticket_no),
foreign key (row_no)
references Seat(row_no),
foreign key (performance_id)
references Performance(id)
);
If I run this query I can get the already booked seats with all the information:
SELECT
b.customer_name,
b.row_no,
s.zone_name,
ROUND(P.base_price * z.price_multiplier, 2) as ticket_price,
p.title,
p.date_time
FROM
Seat s
JOIN Booking b
ON s.row_no = b.row_no
JOIN Performance p
ON p.id = b.performance_id
JOIN Production P
ON p.title = P.title
JOIN Zone z
ON z.name = s.zone_name
WHERE
s.row_no IN
(
SELECT
b.row_no
FROM
Booking b
WHERE
b.performance_id = :perfID
)
;
I figured it out
SELECT
s.row_no,
s.zone_name,
ROUND(z.price_multiplier *
(
SELECT
P.base_price
FROM
Production P
JOIN Performance p
ON P.title = p.title
WHERE
p.id = :perfID
)
, 2) as price
FROM
Seat s
JOIN Zone z
ON s.zone_name = z.name
WHERE
s.row_no NOT IN
(
SELECT
s.row_no
FROM
Seat s
JOIN Booking b
ON s.row_no = b.row_no
WHERE
b.performance_id = :perfID
)
Thanks for your help.

Related

join query does not return null values

I have this table with units/homes
CREATE TABLE `units` (
`id` bigint NOT NULL AUTO_INCREMENT,
`cancellation_policy` varchar(255) DEFAULT NULL,
`description` varchar(255) DEFAULT NULL,
`image_url` varchar(255) NOT NULL,
`price` decimal(19,2) NOT NULL,
`region` varchar(255) NOT NULL,
`title` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `UKha7gwhuig6p6vftvoghfi2b7g` (`title`,`image_url`),
UNIQUE KEY `UK_pdd7pto9vch2kb58kohy96a5f` (`image_url`),
UNIQUE KEY `UK_58rre8c1gk28a7d5p6wguiti9` (`title`)
)
and this one with reviews
CREATE TABLE `reviews` (
`id` bigint NOT NULL AUTO_INCREMENT,
`description` varchar(255) DEFAULT NULL,
`stars` int NOT NULL,
`user_id` varchar(255) NOT NULL,
`unit_id` bigint NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `UKc3rd8vjkpbcda34jomifuybu9` (`user_id`,`unit_id`),
KEY `FKbgbdator49pjrbriaktrbv1q2` (`unit_id`),
CONSTRAINT `FKbgbdator49pjrbriaktrbv1q2` FOREIGN KEY (`unit_id`) REFERENCES `units` (`id`)
)
and I want to get all movies together with the average rating. However this query does not return me back movies without ratings (NULL) values. This query does not return movies without ratings
select
u.id, u.cancellation_policy, u.description, u.image_url, u.price, u.region, u.title, round(avg(stars),0) as ratings
from units u
inner join
reviews r
ON u.id = r.unit_id
group by u.id
What is the correct way to get all movies including those w/o stars?
A LEFT JOIN would show you all units even those that have no reviews
SELECT
u.id,
u.cancellation_policy,
u.description,
u.image_url,
u.price,
u.region,
u.title,
ROUND(AVG(IFNULL(stars,0)), 0) AS ratings
FROM
units u
LEFT JOIN
reviews r ON u.id = r.unit_id
GROUP BY u.id
Try a LEFT JOIN instead of the INNER JOIN

SQL Joining 4 tables, only selecting columns from 2

CREATE TABLE user (
userID INT AUTO_INCREMENT PRIMARY KEY,
accountTypeID INT NOT NULL,
userEmail VARCHAR(320) NOT NULL,
userPassword VARCHAR(32) NOT NULL,
userFirst VARCHAR(20) NOT NULL,
userLast VARCHAR(20) NOT NULL,
userPhone VARCHAR(10) NOT NULL,
lastAccess TIMESTAMP NOT NULL,
userRegistry DATE NOT NULL,
FOREIGN KEY (accountTypeID) REFERENCES accountType(accountTypeID));
CREATE TABLE participant (
participantID INT AUTO_INCREMENT PRIMARY KEY,
vehicleID INT NOT NULL,
userID INT NOT NULL,
eventID INT NOT NULL,
participantRegistry DATE NOT NULL,
paymentMethodID INT NOT NULL,
FOREIGN KEY (vehicleID) REFERENCES vehicle(vehicleID),
FOREIGN KEY (userID) REFERENCES user(userID),
FOREIGN KEY (eventID) REFERENCES event(eventID),
FOREIGN KEY (paymentMethodID) REFERENCES paymentMethod(paymentMethodID));
CREATE TABLE vehicle (
vehicleID INT AUTO_INCREMENT PRIMARY KEY,
makeID INT NOT NULL,
vehicleModel VARCHAR(20) NOT NULL,
vehicleYear VARCHAR(4) NOT NULL,
tshirtID INT NOT NULL,
clubID INT NOT NULL,
FOREIGN KEY (makeID) REFERENCES make(makeID),
FOREIGN KEY (tshirtID) REFERENCES tshirt(tshirtID),
FOREIGN KEY (clubID) REFERENCES club(clubID));
CREATE TABLE club (
clubID INT AUTO_INCREMENT PRIMARY KEY,
clubName VARCHAR(20) NOT NULL,
clubLogo BLOB);
$sql="SELECT U.userFirst, U.userLast, C.clubName FROM user AS U, club AS C
INNER JOIN participant AS P
on P.userID = U.userID
INNER JOIN vehicle AS V
on V.vehicleID = P.vehicleID
INNER JOIN club AS C
on C.clubID = V.clubID
ORDER BY C.clubName ASC";
We are trying to get all the clubs and all the members (first and last name) in each club.
The participant and vehicle tables are just needed to link the users table to the club table.
I know it is something simple the server we are using doesn't display sql errors and does not have phpmyadmin.
Thanks to maSTAShuFu, I came to the working result of.
SELECT U.userFirst, U.userLast, C.clubName FROM club AS C
INNER JOIN vehicle AS V
on C.clubID = V.clubID
INNER JOIN participant AS P
on V.vehicleID = P.vehicleID
INNER JOIN user AS U
on P.userID = U.userID
ORDER BY C.clubName ASC

sum of column returning double the value

I have the following SQL query:
SELECT s.name, s.learner_tag, s.guild_id, s.id, ifnull(sum(t.xp),0) as xp, ifnull(sum(a.ap),0) as ap, (ifnull(sum(t.xp),0)/1000+ifnull(sum(a.ap),0)/100) as level, g.name
FROM student s
INNER JOIN guild g ON g.id = s.guild_id
LEFT JOIN student_task t ON s.id = t.student_id
LEFT JOIN student_achievement a ON s.id = a.student_id
WHERE s.class_id = ".$realm_id."
GROUP BY s.name, s.learner_tag, s.guild_id, s.id, g.name
ORDER BY level DESC LIMIT 10";
However the query returns double the expected value for the ap column. There is only 1 record in the student_achievement table and the value is 25. However my query returns 50 as the value of sum(a.ap). If I edit the value, it still doubles. sum(t.xp) is working fine. Can anyone spot my mistake?
Table Structure:
CREATE TABLE student
(
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
name VARCHAR(64) NOT NULL,
guild_id INT,
class_id INT NOT NULL,
time_updated INT,
ap INT NOT NULL,
learner_tag VARCHAR(64) NOT NULL,
schoology_id INT NOT NULL,
enrollment_id INT NOT NULL,
FOREIGN KEY (guild_id) REFERENCES guild (id),
FOREIGN KEY (class_id) REFERENCES class (id)
);
CREATE TABLE student_achievement
(
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
student_id INT NOT NULL,
achievement_id INT NOT NULL,
time_added INT,
ap INT NOT NULL,
FOREIGN KEY (student_id) REFERENCES student (id),
FOREIGN KEY (achievement_id) REFERENCES achievement (id)
);
CREATE TABLE achievement
(
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
name VARCHAR(64) NOT NULL,
value INT NOT NULL,
repeatable TINYINT NOT NULL,
image_url VARCHAR(200) NOT NULL,
description VARCHAR(240) NOT NULL
);
CREATE TABLE task
(
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
name VARCHAR(64) NOT NULL,
max_xp INT,
schoology_id INT,
class_id INT NOT NULL,
processed TINYINT,
type VARCHAR(15) NOT NULL,
FOREIGN KEY (class_id) REFERENCES class (id)
);

How can I build this query in mysql

Hope someone will help me to build this query. I need to get values from database which are belong to one particular user. These are the columns which I need to get.
01. city_name // From city table
02. district_name // From district table
03. category_name // From category table
04. subscription_period // From tutors table
05. date_registered // From tutors table
I have already got values tutor_id, city_id and category_id respectively 1, 53, 5
My address table has city_id column, City table has district_id column, category table has category_id column and tutor table has tutor_id and address_id.
I tried something like this, but this is not working.
SELECT city_name, district_name, category_name, subscription_period AS sp, date_registered AS date
FROM tutors AS t
INNER JOIN district AS d
INNER JOIN city ON city.district_id = d.district_id
INNER JOIN address ON address.city_id = 50
INNER JOIN category
WHERE t.tutor_id = 1 AND category.category_id= 5
My expecting result should have 1 row as output but this query give me more rows as output
My SQL Tables
CREATE TABLE tutors (
tutor_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
address_id SMALLINT NOT NULL,
tutor_name VARCHAR(80) NOT NULL,
subscription_period SMALLINT NOT NULL,
date_registered TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (tutor_id)
);
CREATE TABLE address (
address_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
address VARCHAR(40) NOT NULL,
city_id SMALLINT UNSIGNED NOT NULL,
PRIMARY KEY (address_id)
);
CREATE TABLE district(
district_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
district_name VARCHAR(30) NOT NULL,
PRIMARY KEY (district_id)
);
CREATE TABLE city(
city_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
city_name VARCHAR(30) NOT NULL,
district_id SMALLINT UNSIGNED NOT NULL,
PRIMARY KEY (city_id)
);
CREATE TABLE category (
category_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
category_name VARCHAR(60) NOT NULL,
PRIMARY KEY (category_id)
);
CREATE TABLE tutor_category(
tutor_id SMALLINT UNSIGNED NOT NULL,
category_id SMALLINT UNSIGNED NOT NULL,
PRIMARY KEY (tutor_id)
);
Try something like this:
SELECT c.city_name,
d.district_name,
c.category_name,
t.subscription_period AS sp,
t.date_registered AS date
FROM tutors t
INNER JOIN address a ON t.address_id = a.address_id
INNER JOIN city c ON c.city_id = a.city_id
INNER JOIN district d ON c.district_id = d.district_id
INNER JOIN tutor_category tc on t.tutor_id = tc.tutor_id
INNER JOIN category cat on tc.category_id = cat.category_id
WHERE t.tutor_id = 1 AND cat.category_id= 5 AND c.city_id = 50
You need to JOIN on your tables to ensure you only receive the desired results.
If you are receiving duplicate rows that are identical, you are probably doing something wrong or the definitions you provided are not correct (it appears that this is the case indeed). You could "solve" the issue by adding GROUP BY or DISTINCT to your query but that is not the best approach.

How can I select the current holder for each championship?

I want to select the current holders for each championship in a championships table, and return NULL for championships that have not had any winners yet.
Here are the create statements for the two tables:
CREATE TABLE `championships` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`friendly_name` varchar(255) NOT NULL,
`rank` int(2) unsigned NOT NULL DEFAULT '1',
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`),
UNIQUE KEY `friendly_name` (`friendly_name`)
) ENGINE=InnoDB;
CREATE TABLE `title_history` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`championship` int(10) unsigned NOT NULL,
`winner` varchar(255) NOT NULL,
`date_from` date NOT NULL,
`location` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
KEY `championship` (`championship`)
) ENGINE=InnoDB;
ALTER TABLE `title_history` ADD CONSTRAINT `title_history_ibfk_1` FOREIGN KEY (`championship`) REFERENCES `championships` (`id`) ON UPDATE CASCADE;
What MySQL statement would return the data set I wanted?
Assuming you're storing the winner of a championship as the primary key/id of the holder, something like this should work. You might want to add in another join to get the actual name of the team from another table though.
Because LEFT join will only select rows from the 'right' table when there is a match, everything that doesn't have one should come back as NULL.
SELECT name, [holder]
FROM championships AS c
LEFT JOIN title_history AS h ON c.winner = h.id
EDITED VERSION:
With further insight into your tables and from your comment, maybe try this subselect:
SELECT friendly_name,
(SELECT winner FROM title_history WHERE championship = c.id ORDER BY date_from DESC LIMIT 1)
FROM championships AS c
ORDER BY name
If I understand your structure correctly, that ought to get the last winner of each championship?