MySQL query: display only graded student essays - mysql

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

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.

Joining different tables based on column value

I have a table called notifications:
CREATE TABLE `notifications` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL,
`type` varchar(20) NOT NULL DEFAULT '',
`parent_id` int(11) DEFAULT NULL,
`parent_type` varchar(15) DEFAULT NULL,
`type_id` int(11) DEFAULT NULL,
`etc` NULL
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8;
Each notification is related to a different table, the value of parent_type field specifies the name of the table that I want to * join the table with. All target tables have several similar columns:
CREATE TABLE `tablename` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`is_visible` tinyint(1) NOT NULL,
`etc` NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
Currently I'm using this query for selecting notifcations that their related row in the target table exists and their is_visible field is 1:
SELECT n.id,
FROM notifications n
LEFT JOIN books b ON n.parent_id = b.id AND n.parent_type = 'book' AND b.is_visible = 1
LEFT JOIN interviews i ON n.parent_id = i.id AND n.parent_type = 'interview' AND i.is_visible = 1
LEFT JOIN other tables...
WHERE n.user_id = 1
GROUP BY n.id
But since it is a LEFT JOIN it returns the notification if it matches any table or not, how can I rewrite it so it doesn't return notifications that don't match with any row in the target table? I have also tried the CASE statement unsuccessfully.
I'm not 100% sure the syntax is right and I have no chance to test it right now, but the idea should be clear.
SELECT DISTINCT n.id
FROM notifications n
JOIN (
(SELECT b.id, 'book' AS type FROM books b WHERE b.is_visible = 1)
UNION
(SELECT i.id, 'interview' AS type FROM interviews i WHERE i.is_visible = 1)
) ids ON n.parent_id = ids.id AND n.parent_type = ids.type
WHERE n.user_id = 1

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.

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