How can I build this query in mysql - 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.

Related

Get tickets available with their price

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.

returning a query with 3 table joins- one being an outer join

i am building a car booking system, the query i need to build is one that displays all the cars in the system- but each car can be booked by 2 people at the same time.
I only want to display cars that have not been fully booked or only have been booked by a single person. I want to be able to see the persons first name and last name if it has been booked by a single person so others can tell who they will be driving with.
This is my query so far but its returning the first record multiple times
SELECT cars.*, people.first_name, people.last_name
FROM
cars
LEFT JOIN booking on cars.id = booking.car LEFT OUTER JOIN people ON booking.person_1 = people.id
WHERE cars.id NOT IN
(SELECT car
FROM booking WHERE slot = 'morning_drive' AND dated = '2011-11-05' AND person_1 != '' AND person_2 != '') AND cars.type = '911'
Heres the structure of the three tables
CREATE TABLE `cars` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(100) NOT NULL,
`description` text NOT NULL,
`large_img_url` varchar(250) NOT NULL,
`small_img_url` varchar(250) NOT NULL,
`nr` varchar(100) NOT NULL,
`license_plate` varchar(100) NOT NULL,
`exterior_color` varchar(100) NOT NULL,
`interior_color` varchar(100) NOT NULL,
`PDK` tinyint(1) NOT NULL,
`Manual` tinyint(1) NOT NULL,
`type` enum('911','vintage') NOT NULL,
`power` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=27 ;
CREATE TABLE `booking` (
`id` int(11) NOT NULL auto_increment,
`slot` enum('morning_drive','afternoon_loop','return_drive') NOT NULL,
`type` enum('911','vintage_911') NOT NULL,
`car` int(11) NOT NULL,
`person_1` int(11) default NULL,
`person_2` int(11) default NULL,
`dated` date NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=25 ;
CREATE TABLE `people` (
`id` int(11) NOT NULL auto_increment,
`first_name` varchar(50) NOT NULL,
`last_name` varchar(50) NOT NULL,
`organisation` varchar(100) NOT NULL,
`event_date` date NOT NULL,
`wave` varchar(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=454 ;
so how can i have my query only return one row per car basically, displaying only cars that have no (person_2) and no (person_1 or person_2), if the car does have person_1- it will retrieve that persons first_name and last_name
update
i have figured out that the main select query is returning all the rows- i need it restricted to slot = 'morning_drive' AND dated = '2011-11-05' so it shows if a person has booked the car for that time slot but also it needs to return the cars where no user has booked for that timeslot
update 2
based on realising new requirements of the query i have added a left outer join subquery instead of using a full table-
SELECT cars.*, people.first_name, people.last_name
FROM
cars
LEFT OUTER JOIN (SELECT car, person_1 FROM booking WHERE slot = 'morning_drive' AND dated = '2011-11-05' AND booking.person_1 != '' AND booking.person_2 = '') bookings on cars.id = bookings.car LEFT JOIN people ON bookings.person_1 = people.id
WHERE cars.id NOT IN
(SELECT car
FROM booking WHERE slot = 'morning_drive' AND dated = '2011-11-05' AND person_1 != '' AND person_2 != '')
AND cars.type = '911'
this is closer to what i want returned but its not join the people table first_names and last_names- its returning nothing
Try:
SELECT cars.*, people.first_name, people.last_name
FROM cars
JOIN booking on cars.id = booking.car
JOIN people on booking.person_1 = people.id
WHERE booking.slot = 'morning_drive' AND
booking.dated = '2011-11-05' AND
coalesce(booking.person_2,'') = '' AND
cars.type = '911'
UNION
SELECT cars.*, '' first_name, '' last_name
FROM cars
WHERE cars.type = '911' AND
NOT EXISTS
(SELECT NULL FROM booking
WHERE slot = 'morning_drive' AND
dated = '2011-11-05' AND
cars.id = bookings.car)

MySQL query: display only graded student essays

So far I can list all the students essays but I want to be able to display only graded student essays and was wondering how would I be able to do this? What else do I have to add to my MySQL code?
Here is what I got so far with my MySQL code.
SELECT students.*, students_essays.*
FROM students
INNER JOIN students_essays ON students.student_id = students_essays.student_id
ORDER BY students_essays.id DESC
Here is my MySQL tables.
CREATE TABLE students_essays (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
student_id INT UNSIGNED NOT NULL,
content TEXT NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE students (
student_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
student_first_name VARCHAR(255) DEFAULT NULL,
student_last_name VARCHAR(255) DEFAULT NULL,
pass CHAR(40) NOT NULL,
PRIMARY KEY (student_id)
);
CREATE TABLE essays_grades (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
grade_id INT UNSIGNED NOT NULL,
students_essays_id INT UNSIGNED NOT NULL,
student_id INT UNSIGNED NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE grades (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
letter_grade VARCHAR(2) DEFAULT NULL,
grade_points FLOAT UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY (id)
);
Just inner join to the essays_grades table (and the grades table if you want the grade).
SELECT students.*, students_essays.*
FROM students
INNER JOIN students_essays ON students.student_id = students_essays.student_id
INNER JOIN essays_grades ON students_essays.id = essays_grades.students_essays_id
ORDER BY students_essays.id DESC
Here's a few tips... You can alias table names (by providing the alias after the table name in the FROM clause) and stop referring to them by their full names, and you can just say JOIN and it is implied to be an inner join.
SELECT st.*, es.*
FROM students st
JOIN students_essays es ON st.student_id = es.student_id
JOIN essays_grades gr ON es.id = gr.students_essays_id
ORDER BY es.id DESC
Just join the grades table on the essays table and check for an existing record.
SELECT students.*, students_essays.*
FROM students
INNER JOIN students_essays ON students.student_id = students_essays.student_id
INNER JOIN essays_grades ON students_essays.id = essays_grades.students_essays_id
ORDER BY students_essays.id DESC

MySQL COUNT problem

Is there a way I can count how many ungraded essays there are to be displayed? IF so What else do I have to add or take away from my MySQL code?
Thanks for the help in advance!
Here is my MySQL code.
SELECT students.*, students_essays.*
FROM students
INNER JOIN students_essays ON students.student_id = students_essays.student_id
LEFT JOIN essays_grades ON students_essays.id = essays_grades.students_essays_id
WHERE essays_grades.grade_id IS NULL
ORDER BY students_essays.id DESC;
Here is my MySQL tables.
CREATE TABLE students_essays (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
student_id INT UNSIGNED NOT NULL,
content TEXT NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE students (
student_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
student_first_name VARCHAR(255) DEFAULT NULL,
student_last_name VARCHAR(255) DEFAULT NULL,
pass CHAR(40) NOT NULL,
PRIMARY KEY (student_id)
);
CREATE TABLE essays_grades (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
grade_id INT UNSIGNED NOT NULL,
students_essays_id INT UNSIGNED NOT NULL,
student_id INT UNSIGNED NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE grades (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
letter_grade VARCHAR(2) DEFAULT NULL,
grade_points FLOAT UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY (id)
);
As far as I can see you only need to look at 2 tables for this.
SELECT COUNT(*)
FROM students_essays se
WHERE NOT EXISTS(SELECT * FROM
essays_grades ge
WHERE se.id = eg.students_essays_id)
SELECT count(*)
FROM students
INNER JOIN students_essays ON students.student_id = students_essays.student_id
LEFT JOIN essays_grades ON students_essays.id = essays_grades.students_essays_id
WHERE essays_grades.grade_id IS NULL
ORDER BY students_essays.id DESC;

MySQL query: display all ungraded essays

So far I can list all the students essays and graded student essays and was wondering how would I be able to display all ungraded essays? What else do I have to add to my MySQL code?
Here is the code I have so far.
SELECT students.*, students_essays.*
FROM students
INNER JOIN students_essays ON students.student_id = students_essays.student_id
INNER JOIN essays_grades ON students_essays.id = essays_grades.students_essays_id
ORDER BY students_essays.id DESC
Here is my MySQL tables.
CREATE TABLE students_essays (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
student_id INT UNSIGNED NOT NULL,
content TEXT NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE students (
student_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
student_first_name VARCHAR(255) DEFAULT NULL,
student_last_name VARCHAR(255) DEFAULT NULL,
pass CHAR(40) NOT NULL,
PRIMARY KEY (student_id)
);
CREATE TABLE essays_grades (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
grade_id INT UNSIGNED NOT NULL,
students_essays_id INT UNSIGNED NOT NULL,
student_id INT UNSIGNED NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE grades (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
letter_grade VARCHAR(2) DEFAULT NULL,
grade_points FLOAT UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY (id)
);
SELECT students.*, students_essays.*
FROM students
INNER JOIN students_essays ON students.student_id = students_essays.student_id
INNER JOIN essays_grades ON students_essays.id = essays_grades.students_essays_id
INNER JOIN grades ON essays_grades.grade_id = grades.id
WHERE LETTER_GRADE IS NULL
ORDER BY students_essays.id DESC;
I used INNER JOIN, just like you did. Note that an inner join will hide rows in the left table, if no matching entry in the right table is found. Use left join if you want to include those as well.
I assumed that letter_grade is null if the essay is ungraded. If your database will not have a essays_grades row, if an essay is not graded, the query will be simpler:
SELECT students.*, students_essays.*
FROM students
INNER JOIN students_essays ON students.student_id = students_essays.student_id
LEFT JOIN essays_grades ON students_essays.id = essays_grades.students_essays_id
WHERE essays_grades.grade_id IS NULL
ORDER BY students_essays.id DESC;
Is ungraded a letter_grade, e. g. 'UG'?
In this case, add
WHERE letter_grade = 'UG'
before the ORDER BY.
SELECT students.*, students_essays.*
FROM students
INNER JOIN students_essays ON students.student_id = students_essays.student_id
LEFT JOIN essays_grades ON students_essays.id = essays_grades.students_essays_id
WHERE essays_grades.students_essays_id is null
ORDER BY students_essays.id DESC