Skip to content

Instantly share code, notes, and snippets.

@Dav1s-Ops
Forked from case-eee/intermediate_sql.md
Last active August 21, 2023 14:38
Show Gist options
  • Save Dav1s-Ops/1e17ef4c3b6180fc4463c6d3b5b6518a to your computer and use it in GitHub Desktop.
Save Dav1s-Ops/1e17ef4c3b6180fc4463c6d3b5b6518a to your computer and use it in GitHub Desktop.
Intermediate SQL

Intermediate SQL Workshop

  • Run psql
  • You may need to run CREATE DATABASE intermediate_sql;
  • To exit this shell, you can run CTRL d

Create tables

Let's create some tables in the database.

CREATE TABLE students(id SERIAL, name TEXT);
CREATE TABLE classes(id SERIAL, name TEXT, teacher_id INT);
CREATE TABLE teachers(id SERIAL, name TEXT, room_number INT);
CREATE TABLE enrollments(id SERIAL, student_id INT, class_id INT, grade INT);

Add data

Let's insert some students.

INSERT INTO students (name)
VALUES ('Penelope'),
       ('Peter'),
       ('Pepe'),
       ('Parth'),
       ('Priscilla'),
       ('Pablo'),
       ('Puja'),
       ('Patricia'),
       ('Piper'),
       ('Paula'),
       ('Pamela'),
       ('Paige'),
       ('Peggy'),
       ('Pedro'),
       ('Phoebe'),
       ('Pajak'),
       ('Parker'),
       ('Priyal'),
       ('Paxton'),
       ('Patrick');

Let's add some teachers.

INSERT INTO teachers (name, room_number)
VALUES ('Phillips', 456),
       ('Vandergrift', 120),
       ('Mauch', 101),
       ('Patel', 320),
       ('Marquez', 560),
       ('Boykin', 200),
       ('Phlop', 333),
       ('Pendergrass', 222),
       ('Palomo', 323),
       ('Altshuler', 543),
       ('Aleman', 187),
       ('Ashley', 432),
       ('Bonacci', 399),
       ('Brazukas', 287),
       ('Brockington', 299),
       ('Brizuela', 376),
       ('Burkhart', 199),
       ('Choi', 463),
       ('Shah', 354),
       ('Dimaggio', 251);

Let's add some classes.

INSERT INTO classes (name, teacher_id)
VALUES ('Cooking Pasta', 1),
       ('Yoga', 1),
       ('How to Guitar', 2),
       ('Gym', 3),
       ('Football', 4),
       ('Calculus', 5),
       ('Fruit', 6),
       ('Social Studies', 7),
       ('English', 8),
       ('Programming', 9),
       ('Singing', 10),
       ('Fashion', 11);

Lastly, let's add some enrollments!

INSERT INTO enrollments (student_id, class_id, grade)
VALUES (1, 1, 60),
       (2, 2, 70),
       (2, 4, 100),
       (3, 2, 74),
       (4, 3, 82),
       (5, 3, 45),
       (5, 4, 50),
       (7, 11, 62),
       (7, 10, 76),
       (7, 9, 81),
       (7, 8, 91),
       (8, 8, 84),
       (9, 8, 88),
       (9, 7, 83),
       (10, 7, 93),
       (10, 5, 95),
       (11, 5, 95),
       (11, 11, 80),
       (11, 6, 95),
       (11, 1, 94),
       (11, 2, 60),
       (12, 6, 55),
       (13, 7, 97),
       (14, 10, 86),
       (15, 9, 77),
       (15, 4, 93),
       (15, 1, 73),
       (16, 2, 79),
       (16, 6, 73),
       (17, 7, 86),
       (17, 8, 91),
       (17, 9, 93),
       (18, 10, 94),
       (19, 4, 84),
       (20, 1, 85),
       (20, 11, 89),
       (20, 3, 98);

Practice!!

  • List all the students and their classes
  • List all the students and their classes and rename the columns to "student" and "class"
SELECT students.name student_name, classes.name class_name
FROM students
INNER JOIN enrollments ON students.id = enrollments.student_id
INNER JOIN classes ON classes.id = enrollments.class_id;
Student
  .joins(:enrollments, :classes)
  .select('students.name, classes.name')
  • List all the students and their average grade
SELECT students.name student_name, ROUND(AVG(enrollments.grade), 2) avg_grade
FROM students
INNER JOIN enrollments ON students.id = enrollments.student_id
INNER JOIN classes ON classes.id = enrollments.class_id
GROUP BY students.name;
Student
  .joins(:enrollments, :classes)
  .select('students.name, ROUND(AVG(enrollments.grade))')
  .group('students.name')
  • List all the students and a count of how many classes they are currently enrolled in
SELECT students.name student_name, COUNT(classes.id) class_count
FROM students
INNER JOIN enrollments ON students.id = enrollments.student_id
INNER JOIN classes ON classes.id = enrollments.class_id
GROUP BY students.name;
Student
  .joins(:enrollments, :classes)
  .select('students.name, COUNT(classes.id)')
  .group('students.name')
  • List all the students and their class count IF they are in more than 2 classes
SELECT students.name student_name, COUNT(classes.id) class_count
FROM students
INNER JOIN enrollments ON students.id = enrollments.student_id
INNER JOIN classes ON classes.id = enrollments.class_id
GROUP BY students.name
HAVING COUNT(classes.id) > 2;
Student
  .joins(:enrollments, :classes)
  .select('students.name, COUNT(classes.id)')
  .group('students.name')
  .having('COUNT(classes.id) > 2')
  • List all the teachers for each student
  • List all the teachers for each student grouped by each student
SELECT students.name student_name, STRING_AGG(teachers.name, ', ') teacher_name
FROM students
INNER JOIN enrollments ON students.id = enrollments.student_id
INNER JOIN classes ON classes.id = enrollments.class_id
INNER JOIN teachers ON teachers.id = classes.teacher_id
GROUP BY students.name;
Student
  .joins(enrollments: {class: :teacher})
  .select('students.name, STRING_AGG(teachers.name, ', ')')
  .group('students.name')
  • Find the average grade for a each class
SELECT classes.id class_id, ROUND(AVG(enrollments.grade)) avg_grade
FROM enrollments
INNER JOIN classes ON classes.id = enrollments.class_id
GROUP BY classes.id;
Enrollment.
  .joins(:classes)
  .select('classes.id, ROUND(AVG(enrollments.grade)')
  .group('classes.id')
  • List students' name and their grade IF their grade is lower than the average.
SELECT students.name student_name, enrollments.grade student_grade
FROM students
INNER JOIN enrollments ON students.id = enrollments.student_id
INNER JOIN classes ON classes.id = enrollments.class_id
INNER JOIN teachers ON teachers.id = classes.teacher_id
WHERE enrollments.grade < (
    SELECT ROUND(AVG(enrollments.grade))
    FROM enrollments
    WHERE enrollments.class_id = classes.id
);
subquery = Enrollment
  .select('ROUND(AVG(enrollments.grade))')
  .where('enrollments.class_id = classes.id')

result = Student
  .joins(enrollments: { class: :teacher })
  .select('students.name, enrollments.grade')
  .where("enrollments.grade < (#{subquery.to_sql})")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment