Discussion 1
SQL
Agenda
Logistics
Course website: http://www.cs186berkeley.net/
Projects are involved coding assignments
Vitamins are required weekly quizzes that keep you up to date with lectures
Midterm 1 will be on Oct 1st, 8-10PM
Midterm 2 will be on Nov 5th, 8-10PM
Logistics - Access Check
EdStem: https://edstem.org/us/join/xDrU5s
Gradescope: https://www.gradescope.com/courses/1225642
GitHub/Classroom50: See Project 0 for setup
Public Course Drive: https://drive.google.com/drive/folders/1O3AL0ld4Riq8H0f3-eBHUzq4SCNq6bKp
Questions?
Motivation
This week: How do I use SQL to fetch data? (covered much more extensively in data science classes)
The rest of the semester: How does SQL fetch data for me?
SQL
SQL for single tables queries
SELECT [DISTINCT] <column list>�FROM <table1>�[WHERE <predicate>]�[GROUP BY <column list>]�[HAVING <predicate>]�[ORDER BY <column list> [DESC/ASC]]�[LIMIT <amount>];
Logical Processing Order
Logical Processing Order
a | b |
1 | 0 |
2 | 1 |
3 | 0 |
4 | 1 |
5 | 0 |
6 | 1 |
7 | 2 |
8 | 3 |
test_table
�FROM test_table�
Take data FROM test_table.
Logical Processing Order
a | b |
1 | 0 |
2 | 1 |
3 | 0 |
4 | 1 |
5 | 0 |
6 | 1 |
7 | 2 |
8 | 3 |
a | b |
3 | 0 |
4 | 1 |
5 | 0 |
6 | 1 |
7 | 2 |
8 | 3 |
test_table
�FROM test_table�WHERE a > 2�
Take data FROM test_table and keep rows WHERE a > 2.
Logical Processing Order
�FROM test_table�WHERE a > 2�GROUP BY b�
a | b |
3 | 0 |
4 | 1 |
5 | 0 |
6 | 1 |
7 | 2 |
8 | 3 |
We GROUP BY b, but there may be multiple values of a per group, so we can’t use a directly anymore. We can, however, use it with aggregate functions (MIN, MAX, SUM, AVERAGE, COUNT).
Using aggregate functions without a GROUP BY clause = everything in one group.
a | b |
3 | 0 |
5 | 0 |
4 | 1 |
6 | 1 |
7 | 2 |
8 | 3 |
Logical Processing Order
�FROM test_table�WHERE a > 2�GROUP BY b
HAVING COUNT(*) >= 2�
Throw away groups that have fewer than 2 rows in them.
Note: COUNT(*) includes NULL values, and COUNT(column) does not include null values.
a | b |
3 | 0 |
5 | 0 |
4 | 1 |
6 | 1 |
7 | 2 |
8 | 3 |
a | b |
3 | 0 |
5 | 0 |
4 | 1 |
6 | 1 |
Logical Processing Order
c |
0 |
1 |
SELECT b AS c�FROM test_table�WHERE a > 2�GROUP BY b
HAVING COUNT(*) >= 2�
We use an alias here: b AS c selects b, but then calls it c afterwards. We can use this alias in any step after this one (so not in SELECT, WHERE, GROUP BY, HAVING).
a | b |
3 | 0 |
5 | 0 |
4 | 1 |
6 | 1 |
Logical Processing Order
c |
0 |
1 |
SELECT DISTINCT b AS c�FROM test_table�WHERE a > 2�GROUP BY b
HAVING COUNT(*) >= 2�
There are no duplicate rows here so DISTINCT isn’t necessary, but if there were any, DISTINCT would remove them. Duplicates are removed by exact match on the entire row.
c |
0 |
1 |
Logical Processing Order
c |
1 |
0 |
SELECT DISTINCT b AS c�FROM test_table�WHERE a > 2�GROUP BY b
HAVING COUNT(*) >= 2�ORDER BY c DESC
c |
0 |
1 |
Sort the output by the columns (just c here) (numerically for integers, lexicographically for strings) in either ASCending (low to high) or DESCending (high to low) order. Default is ASC.
Note: order of output is not guaranteed unless you have an ORDER BY clause.
Logical Processing Order
c |
1 |
SELECT DISTINCT b AS c�FROM test_table�WHERE a > 2�GROUP BY b
HAVING COUNT(*) >= 2�ORDER BY c DESC
LIMIT 1
c |
1 |
0 |
Return just the first row.
A Note On GROUP BY
Dept | Course | Capacity |
CS | 186 | 715 |
CS | 161 | 485 |
EE | 16B | 580 |
EE | 105 | 40 |
DATA | 100 | 1375 |
Dept | Course | Capacity |
CS | 186 | 715 |
CS | 161 | 485 |
EE | 16B | 580 |
EE | 105 | 40 |
DATA | 100 | 1375 |
A Note On GROUP BY
Dept | Course | Capacity |
CS | 186 | 715 |
CS | 161 | 485 |
EE | 16B | 580 |
EE | 105 | 40 |
DATA | 100 | 1375 |
SELECT Dept, Course �FROM Classes GROUP BY Dept;
Dept | Course |
CS | ? |
EE | ? |
DATA | ? |
Are the following valid?
NO
SELECT Dept, SUM(Capacity) FROM Classes GROUP BY Dept;
Dept | SUM(Cap.) |
CS | 1200 |
EE | 620 |
DATA | 1375 |
YES
The Group By Rules
Given the table Students(sid, age, gpa, name, major), which of the following are valid?
SELECT age�FROM Students
GROUP BY major;
SELECT age�FROM Students
GROUP BY major, age;
SELECT MAX(age)�FROM Students
GROUP BY major;
SELECT age, MIN(gpa)�FROM Students
GROUP BY name;
NO
YES
YES
NO
String Comparison
LIKE: following expression follows SQL specified format
Examples:
~ : following expression follows regex format
Examples:
Note: ~ cannot be used in SQLite (which Project 1 will be using)
Practice: Single-Table Queries
Question 1a
Find the names of the 5 songs that spent the least weeks in the top 40, ordered from least to most. Break ties by song name in alphabetical order.
Tables
Songs �(song_id, song_name, album_id, weeks_in_top_40)
Artists �(artist_id, artist_name, first_yr_active)
Albums �(album_id, album_name, artist_id, yr_released, genre)
Question 1a
Find the names of the 5 songs that spent the least weeks in the top 40, ordered from least to most. Break ties by song name in alphabetical order.
Tables
Songs �(song_id, song_name, album_id, weeks_in_top_40)
Artists �(artist_id, artist_name, first_yr_active)
Albums �(album_id, album_name, artist_id, yr_released, genre)
SELECT song_name
FROM Songs
ORDER BY weeks_in_top_40 ASC, song_name ASC
LIMIT 5
Question 1b
Find the name and first year active of every artist whose name starts with the letter ‘B’.
Tables
Songs �(song_id, song_name, album_id, weeks_in_top_40)
Artists �(artist_id, artist_name, first_yr_active)
Albums �(album_id, album_name, artist_id, yr_released, genre)
Question 1b
Find the name and first year active of every artist whose name starts with the letter ‘B’.
Tables
Songs �(song_id, song_name, album_id, weeks_in_top_40)
Artists �(artist_id, artist_name, first_yr_active)
Albums �(album_id, album_name, artist_id, yr_released, genre)
SELECT artist_name, first_yr_active�FROM artists�WHERE artist_name LIKE 'B%'
Question 1b
Find the name and first year active of every artist whose name starts with the letter ‘B’.
Tables
Songs �(song_id, song_name, album_id, weeks_in_top_40)
Artists �(artist_id, artist_name, first_yr_active)
Albums �(album_id, album_name, artist_id, yr_released, genre)
SELECT artist_name, first_yr_active�FROM artists�WHERE artist_name ~ '^B.*'
Question 1c
Find the total number of albums released per genre.
Tables
Songs �(song_id, song_name, album_id, weeks_in_top_40)
Artists �(artist_id, artist_name, first_yr_active)
Albums �(album_id, album_name, artist_id, yr_released, genre)
Question 1c
Find the total number of albums released per genre.
Tables
Songs �(song_id, song_name, album_id, weeks_in_top_40)
Artists �(artist_id, artist_name, first_yr_active)
Albums �(album_id, album_name, artist_id, yr_released, genre)
SELECT genre, COUNT(album_id)
FROM Albums
GROUP BY genre;
Question 1d
Find the total number of albums released per genre. Don’t include genres with a count less than 10.
Tables
Songs �(song_id, song_name, album_id, weeks_in_top_40)
Artists �(artist_id, artist_name, first_yr_active)
Albums �(album_id, album_name, artist_id, yr_released, genre)
Question 1d
Find the total number of albums released per genre. Don’t include genres with a count less than 10.
Tables
Songs �(song_id, song_name, album_id, weeks_in_top_40)
Artists �(artist_id, artist_name, first_yr_active)
Albums �(album_id, album_name, artist_id, yr_released, genre)
SELECT genre, COUNT(*)
FROM Albums
GROUP BY genre
HAVING COUNT(*) >= 10;
Question 1e
Find the genre for which the most albums were released in the year 2000. Assume there are no ties.
Tables
Songs �(song_id, song_name, album_id, weeks_in_top_40)
Artists �(artist_id, artist_name, first_yr_active)
Albums �(album_id, album_name, artist_id, yr_released, genre)
Question 1e
Find the genre for which the most albums were released in the year 2000. Assume there are no ties.
Tables
Songs �(song_id, song_name, album_id, weeks_in_top_40)
Artists �(artist_id, artist_name, first_yr_active)
Albums �(album_id, album_name, artist_id, yr_released, genre)
SELECT genre
FROM Albums
WHERE yr_released = 2000
GROUP BY genre
ORDER BY COUNT(*) DESC
LIMIT 1;
SQL Joins
Join Variants
SELECT * FROM
T1 INNER JOIN T2
ON T1.a = T2.a;
Join Condition
Inner Join, Example
Name | Age |
Brian | 20 |
Lakshya | 22 |
Kimberly | 22 |
Kimberly | 18 |
Ages
Name | Year |
Brian | Junior |
Kimberly | Freshman |
Ben | Senior |
Standing
SELECT ages.Name, ages.Age, standing.Year
FROM ages INNER JOIN standing
ON ages.Name = standing.Name;
Inner Join, Example
Name | Age |
Brian | 20 |
Lakshya | 22 |
Kimberly | 22 |
Kimberly | 18 |
Ages
Name | Year |
Brian | Junior |
Kimberly | Freshman |
Ben | Senior |
Standing
SELECT ages.Name, ages.Age, standing.Year
FROM ages INNER JOIN standing
ON ages.Name = standing.Name;
Name | Age | Year |
Brian | 20 | Junior |
Result
Inner Join, Example
Name | Age |
Brian | 20 |
Lakshya | 22 |
Kimberly | 22 |
Kimberly | 18 |
Ages
Name | Year |
Brian | Junior |
Kimberly | Freshman |
Ben | Senior |
Standing
SELECT ages.Name, ages.Age, standing.Year
FROM ages INNER JOIN standing
ON ages.Name = standing.Name;
Name | Age | Year |
Brian | 20 | Junior |
Result
Inner Join, Example
Name | Age |
Brian | 20 |
Lakshya | 22 |
Kimberly | 22 |
Kimberly | 18 |
Ages
Name | Year |
Brian | Junior |
Kimberly | Freshman |
Ben | Senior |
Standing
SELECT ages.Name, ages.Age, standing.Year
FROM ages INNER JOIN standing
ON ages.Name = standing.Name;
Name | Age | Year |
Brian | 20 | Junior |
Result
Inner Join, Example
Name | Age |
Brian | 20 |
Lakshya | 22 |
Kimberly | 22 |
Kimberly | 18 |
Ages
Name | Year |
Brian | Junior |
Kimberly | Freshman |
Ben | Senior |
Standing
SELECT ages.Name, ages.Age, standing.Year
FROM ages INNER JOIN standing
ON ages.Name = standing.Name;
Name | Age | Year |
Brian | 20 | Junior |
Result
Inner Join, Example
Name | Age |
Brian | 20 |
Lakshya | 22 |
Kimberly | 22 |
Kimberly | 18 |
Ages
Name | Year |
Brian | Junior |
Kimberly | Freshman |
Ben | Senior |
Standing
SELECT ages.Name, ages.Age, standing.Year
FROM ages INNER JOIN standing
ON ages.Name = standing.Name;
Name | Age | Year |
Brian | 20 | Junior |
Result
Inner Join, Example
Name | Age |
Brian | 20 |
Lakshya | 22 |
Kimberly | 22 |
Kimberly | 18 |
Ages
Name | Year |
Brian | Junior |
Kimberly | Freshman |
Ben | Senior |
Standing
SELECT ages.Name, ages.Age, standing.Year
FROM ages INNER JOIN standing
ON ages.Name = standing.Name;
Name | Age | Year |
Brian | 20 | Junior |
Result
Inner Join, Example
Name | Age |
Brian | 20 |
Lakshya | 22 |
Kimberly | 22 |
Kimberly | 18 |
Ages
Name | Year |
Brian | Junior |
Kimberly | Freshman |
Ben | Senior |
Standing
SELECT ages.Name, ages.Age, standing.Year
FROM ages INNER JOIN standing
ON ages.Name = standing.Name;
Name | Age | Year |
Brian | 20 | Junior |
Result
Inner Join, Example
Name | Age |
Brian | 20 |
Lakshya | 22 |
Kimberly | 22 |
Kimberly | 18 |
Ages
Name | Year |
Brian | Junior |
Kimberly | Freshman |
Ben | Senior |
Standing
SELECT ages.Name, ages.Age, standing.Year
FROM ages INNER JOIN standing
ON ages.Name = standing.Name;
Name | Age | Year |
Brian | 20 | Junior |
Kimberly | 22 | Freshman |
Result
Inner Join, Example
Name | Age |
Brian | 20 |
Lakshya | 22 |
Kimberly | 22 |
Kimberly | 18 |
Ages
Name | Year |
Brian | Junior |
Kimberly | Freshman |
Ben | Senior |
Standing
SELECT ages.Name, ages.Age, standing.Year
FROM ages INNER JOIN standing
ON ages.Name = standing.Name;
Name | Age | Year |
Brian | 20 | Junior |
Kimberly | 22 | Freshman |
Result
Inner Join, Example
Name | Age |
Brian | 20 |
Lakshya | 22 |
Kimberly | 22 |
Kimberly | 18 |
Ages
Name | Year |
Brian | Junior |
Kimberly | Freshman |
Ben | Senior |
Standing
SELECT ages.Name, ages.Age, standing.Year
FROM ages INNER JOIN standing
ON ages.Name = standing.Name;
Name | Age | Year |
Brian | 20 | Junior |
Kimberly | 22 | Freshman |
Result
Inner Join, Example
Name | Age |
Brian | 20 |
Lakshya | 22 |
Kimberly | 22 |
Kimberly | 18 |
Ages
Name | Year |
Brian | Junior |
Kimberly | Freshman |
Ben | Senior |
Standing
SELECT ages.Name, ages.Age, standing.Year
FROM ages INNER JOIN standing
ON ages.Name = standing.Name;
Name | Age | Year |
Brian | 20 | Junior |
Kimberly | 22 | Freshman |
Kimberly | 18 | Freshman |
Result
Inner Join, Example
Name | Age |
Brian | 20 |
Lakshya | 22 |
Kimberly | 22 |
Kimberly | 18 |
Ages
Name | Year |
Brian | Junior |
Kimberly | Freshman |
Ben | Senior |
Standing
SELECT ages.Name, ages.Age, standing.Year
FROM ages INNER JOIN standing
ON ages.Name = standing.Name;
Name | Age | Year |
Brian | 20 | Junior |
Kimberly | 22 | Freshman |
Kimberly | 18 | Freshman |
Result
Inner Join, Example
Name | Age |
Brian | 20 |
Lakshya | 22 |
Kimberly | 22 |
Kimberly | 18 |
Ages
Name | Year |
Brian | Junior |
Kimberly | Freshman |
Ben | Senior |
Standing
SELECT ages.Name, ages.Age, standing.Year
FROM ages INNER JOIN standing
ON ages.Name = standing.Name;
Name | Age | Year |
Brian | 20 | Junior |
Kimberly | 22 | Freshman |
Kimberly | 18 | Freshman |
Result
Left Join, Example
Name | Age |
Brian | 20 |
Lakshya | 22 |
Kimberly | 22 |
Kimberly | 18 |
Ages
Name | Year |
Brian | Junior |
Kimberly | Freshman |
Ben | Senior |
Standing
SELECT ages.Name, ages.Age, standing.Year
FROM ages LEFT JOIN standing
ON ages.Name = standing.Name;
Left Join, Example
Name | Age |
Brian | 20 |
Lakshya | 22 |
Kimberly | 22 |
Kimberly | 18 |
Ages
Name | Year |
Brian | Junior |
Kimberly | Freshman |
Ben | Senior |
Standing
SELECT ages.Name, ages.Age, standing.Year
FROM ages LEFT JOIN standing
ON ages.Name = standing.Name;
Name | Age | Year |
Brian | 20 | Junior |
Kimberly | 22 | Freshman |
Kimberly | 18 | Freshman |
Lakshya | 22 | null |
Result
Right Join, Example
Name | Age |
Brian | 20 |
Lakshya | 22 |
Kimberly | 22 |
Kimberly | 18 |
Ages
Name | Year |
Brian | Junior |
Kimberly | Freshman |
Ben | Senior |
Standing
SELECT ages.Name, ages.Age, standing.Year
FROM ages RIGHT JOIN standing
ON ages.Name = standing.Name;
Right Join, Example
SELECT ages.Name, ages.Age, standing.Year
FROM ages RIGHT JOIN standing
ON ages.Name = standing.Name;
ages.Name | ages.Age | standing.Name | standing.Year |
Brian | 20 | Brian | Junior |
Kimberly | 22 | Kimberly | Freshman |
Kimberly | 18 | Kimberly | Freshman |
null | null | Ben | Senior |
Intermediate Table (Before SELECT)
Right Join, Example
Name | Age |
Brian | 20 |
Lakshya | 22 |
Kimberly | 22 |
Kimberly | 18 |
Ages
Name | Year |
Brian | Junior |
Kimberly | Freshman |
Ben | Senior |
Standing
SELECT ages.Name, ages.Age, standing.Year
FROM ages RIGHT JOIN standing
ON ages.Name = standing.Name;
Name | Age | Year |
Brian | 20 | Junior |
Kimberly | 22 | Freshman |
Kimberly | 18 | Freshman |
null | null | Senior |
Result
Full Outer Join, Example
Name | Age |
Brian | 20 |
Lakshya | 22 |
Kimberly | 22 |
Kimberly | 18 |
Ages
Name | Year |
Brian | Junior |
Kimberly | Freshman |
Ben | Senior |
Standing
SELECT ages.Name, ages.Age, standing.Year
FROM ages FULL JOIN standing
ON ages.Name = standing.Name;
Full Outer Join, Example
Name | Age |
Brian | 20 |
Lakshya | 22 |
Kimberly | 22 |
Kimberly | 18 |
Ages
Name | Year |
Brian | Junior |
Kimberly | Freshman |
Ben | Senior |
Standing
SELECT ages.Name, ages.Age, standing.Year
FROM ages FULL JOIN standing
ON ages.Name = standing.Name;
Name | Age | Year |
Brian | 20 | Junior |
Kimberly | 22 | Freshman |
Kimberly | 18 | Freshman |
null | null | Senior |
Lakshya | 22 | null |
Result
Practice: Multi-Table Joins
Question 2a
Find the names of all artists who released a ‘country’ genre album in 2020.
Tables
Songs �(song_id, song_name, album_id, weeks_in_top_40)
Artists �(artist_id, artist_name, first_yr_active)
Albums �(album_id, album_name, artist_id, yr_released, genre)
Question 2a
Find the names of all artists who released a ‘country’ genre album in 2020.
Tables
Songs �(song_id, song_name, album_id, weeks_in_top_40)
Artists �(artist_id, artist_name, first_yr_active)
Albums �(album_id, album_name, artist_id, yr_released, genre)
SELECT artist_name
FROM Artists AS A
INNER JOIN Albums AS B
ON A.artist_id = B.artist_id
WHERE genre = ‘country’ AND yr_released = 2020
GROUP BY A.artist_id, artist_name;
Question 2b
Find the name of the album with the song that spend the most weeks in the top 40. Assume there is only one such song.
Tables
Songs �(song_id, song_name, album_id, weeks_in_top_40)
Artists �(artist_id, artist_name, first_yr_active)
Albums �(album_id, album_name, artist_id, yr_released, genre)
Question 2b
Find the name of the album with the song that spend the most weeks in the top 40. Assume there is only one such song.
Tables
Songs �(song_id, song_name, album_id, weeks_in_top_40)
Artists �(artist_id, artist_name, first_yr_active)
Albums �(album_id, album_name, artist_id, yr_released, genre)
SELECT album_name
FROM Albums AS A INNER JOIN Songs AS S �ON A.album_id = S.album_id
ORDER BY weeks_in_top_40 DESC LIMIT 1;
Question 2c
Find the artist name and the most weeks one of their songs spent in the top 40 for each artist. Include artists that have not released an album.
Tables
Songs �(song_id, song_name, album_id, weeks_in_top_40)
Artists �(artist_id, artist_name, first_yr_active)
Albums �(album_id, album_name, artist_id, yr_released, genre)
Question 2c
Find the artist name and the most weeks one of their songs spent in the top 40 for each artist. Include artists that have not released an album.
Tables
Songs �(song_id, song_name, album_id, weeks_in_top_40)
Artists �(artist_id, artist_name, first_yr_active)
Albums �(album_id, album_name, artist_id, yr_released, genre)
SELECT artist_name, MAX(weeks_in_top_40)
FROM Artists LEFT JOIN
(Songs INNER JOIN Albums ON Songs.album_id = Albums.album_id)
ON Artists.artist_id = Albums.artist_id
GROUP BY Artists.artist_id, artist_name;
Appendix (Tips and Tricks)
Attendance Link