SQL_ALL
SQL_ALL
Check out the postgres tips on the course webpage to try this yourself
Case convention
• SQL is completely case insensitive (except in text values)
• We will use case in the following way to make code readable:
• UPPERCASE marks keywords of the SQL language.
• lowercase marks the name of an attribute.
• Capitalized marks the name of a table.
• These queries do the same thing, but only the first follows our convention:
SELECT attribute FROM Data WHERE attribute2 = something;
Here, student is both part of the primary key, and a foreign key
Multiple foreign keys
Unlike primary keys, a table can have any
number of foreign key constraints
CREATE TABLE Grades (
student TEXT, Each constraint is checked independently
course CHAR(6),
grade INT,
and valid data must satisfy all constraints
PRIMARY KEY (student, course),
FOREIGN KEY (student) REFERENCES Students(idNumber),
FOREIGN KEY (course) REFERENCES Courses(courseCode)
);
Informally: "student must be an actual student,
course must be an actual course"
A player has a player-number and
Compound references belongs to a team (within each
team, players have unique numbers)
CREATE TABLE Player (
pname TEXT,
team TEXT,
pnumber INT,
PRIMARY KEY (team,pnumber)
); A penalty can be given to a player
CREATE TABLE Penalties ( Constraint: player and team
incidentTime TIMESTAMP, together identify an existing player
player INT,
team TEXT,
PRIMARY KEY (incidentTime, player, team),
FOREIGN KEY (player,team) REFERENCES Player(pnumber,team)
);
Unique constraints
• Some tables have several keys (but one of them is always primary)
• Additional keys can be marked as UNIQUE, and the DBMS will prevent
inserting rows with duplicate values
CREATE TABLE Students (
idNumber TEXT, cid (username) must have
name TEXT, unique values for each student
cid CHAR(7),
UNIQUE (cid),
PRIMARY KEY (idNumber)
Works (no collisions)
);
• Each course can only give at most one grade to a single student
Primary key problem 3
• What is the problem with this relation?
Grades(student, course, grade)
Also works
Works – no collisions
student course grade
student course grade
790401-1234 TDA143 0
790401-1234 TDA357 0
790401-1234 TDA143 3
790401-1234 TDA143 3
790401-1234 TDA143 4
810509-0123 TDA143 5
Works!
student course grade
student course grade
790401-1234 TDA143 0
790401-1234 TDA357 0
790401-1234 TDA143 3
790401-1234 TDA143 3
790401-1234 TDA143 4
810509-0123 TDA143 5
• Spoiler alert: The last view takes *a lot* more time than the previous ones
SQL Queries
• The result of each query is a table
• Example: Fetch personal number for each student that has a grade in TDA143:
Which columns? From what table? Condition that each row must satisfy
SELECT student FROM Grades WHERE course = 'TDA143';
Table: Grades
student course grade
student
790401-1234 TDA357 0
790401-1234
790401-1234 TDA143 0
810509-0123
810509-0123 TDA143 5
Execution of a SQL-Query FROM Grades
SELECT student
student course grade
FROM Grades
790401-1234 TDA357 0
WHERE course = 'TDA143';
790401-1234 TDA143 0
810509-0123 TDA143 5
student
790401-1234 WHERE course = 'TDA143'
810509-0123
Table: Grades
student course grade
student grade 790401-1234 TDA357 3
810509-0123 5 790401-1234 TDA143 0
810509-0123 TDA143 5
Cartesian product
• Operation in set theory (thus applicable to relations!)
• If S = {1,2,3} T = {A, B, C} then the product S X T is all combinations (pairs):
{(1,A), (1,B), (1,C), (2,A), (2,B), (2,C), (3,A), (3,B), (3,C)}
• In general, if N=|S| and M=|T| then N*M = |S XT|
(Example: S has three elements and T has four, so S X T has twelve element)
student course code points
790401-1234 TDA357 TDA357 7.5
student course
code points 790401-1234 TDA357 TDA143 7.5
X
790401-1234 TDA357
790401-1234 TDA143
TDA357 7.5 = 790401-1234 TDA143 TDA357 7.5
TDA143 7.5 790401-1234 TDA143 TDA143 7.5
810509-0123 TDA143
810509-0123 TDA143 TDA357 7.5
810509-0123 TDA143 TDA143 7.5
3+3 = 6 columns
Table: Students
Join-operation idNumber
790401-1234
name
Bart Simpson
CID
barsimp
• Suppose we want the name of everyone with a 810509-0123 Lisa Simpson simpsol
grade in TDA143 Table: Grades
student course grade
• Look at the Cartesian product of Students and
Grades (Students X Grades)
790401-1234 TDA357 0
790401-1234 TDA143 0
• The rows where the personal numbers match are 810509-0123 TDA143 5
the relevant ones, the rest are nonsense
idNumber name CID student course grade
790401-1234 Bart Simpson barsimp 790401-1234 TDA357 0
790401-1234 Bart Simpson barsimp 790401-1234 TDA143 0
790401-1234 Bart Simpson barsimp 810509-0123 TDA143 5
810509-0123 Lisa Simpson simpsol 790401-1234 TDA357 0
810509-0123 Lisa Simpson simpsol 790401-1234 TDA143 0
810509-0123 Lisa Simpson simpsol 810509-0123 TDA143 5
SELECT idNumber, name, grade
FROM Students, Grades
WHERE (idNumber=student) AND (course='TDA143');
name
Bart Simpson
Each name is repeated for every
Bart Simpson course taken by a student with
Lisa Simpson that name
Summary: basic SQL-expressions
SELECT attribute1, attrubute2 ...
FROM Table1, Table2 ...
WHERE Condition (attribute1 = attrubute2 OR attribute3 = 'text')
• What does this query yield? (how many rows?) Bart 11111
SELECT name,phone,email
FROM Phones LEFT OUTER JOIN Emails USING (name);
COALESCE
• COALESCE takes a list of values and returns the first non-null value
• Typical use case: Replaces null values with constants (of matching type)
SELECT name, COALESCE(email, 'no email') AS email
FROM Emails FULL OUTER JOIN …
2 rows
Table: Lectures Table: Exercises
ltime lroom teacher etime eroom subject
• Takes the intersection of two queries (all rows that appear in both)
Result:
(SELECT lroom,ltime FROM Lectures)
lroom ltime
INTERSECT
GD 11-06 8:00
(SELECT eroom,etime FROM Exercises);
Table: Lectures Table: Exercises
ltime lroom teacher etime eroom subject
Result:
(SELECT lroom,ltime FROM Lectures)
EXCEPT lroom ltime
Ordering Bart
Lisa
44444
22222
• Sometimes, the order of rows in the result is important Bart 33333
for the user Homer 11111
? student
Bart
Lisa
AVG
3.0
4.5
Bart Project 0
• To do this, I need to tell SQL to group all the values in Grades by the student
attribute (two groups) then for each group select the (unique) student and
compute the average of the grades in the group
SELECT student, AVG(grade)
FROM Grades
WHERE grade >= 3 The selected columns must be a subset of
GROUP BY student; the columns we group by!
(Selecting course here would not make sense)
Table: Grades
Table: Courses
student course grade
name points
Quiz Databases 10
Lisa Databases 4
Lisa Project 5
Project 15
Bart Databases 3
Bart Project 0
• For each course, lists its name, points and number of passed students
• Start with FROM, then WHERE, then SELECT and GROUP BY
SELECT name, points, COUNT(*) AS passed
FROM Courses, Grades
name points passed
WHERE course = name
Databases 10 2
AND grade >= 3
Project 15 1
GROUP BY (name,points);
HAVING
• What if I want to list all students with an average above 4?
• This does not work (the WHERE-clause resolves before the grouping!)
SELECT student
FROM Grades
WHERE grade >= 3 AND AVG(grade) > 4
GROUP BY student;
• SQL has a special clause for conditions on groups, called HAVING
SELECT student
FROM Grades Resolved before grouping (to exclude 0)
WHERE grade >= 3
GROUP BY student
Resolved during grouping
HAVING AVG(grade) > 4;
(condition for each group)
Where can you have subqueries?
• Where can you not have subqueries?!
• You can have them in FROM
Cartesian product of a table and a query result
SELECT name
FROM Courses, (SELECT course, COUNT(*) AS graded
FROM Grades GROUP BY course) AS Q
WHERE Courses.name = Q.course AND Q.graded > 100;
• You can have them in WHERE
SELECT * FROM Grades Select all above average grades
WHERE grade > (SELECT AVG(grade) FROM Grades);
Comparison only works if subquery gives a single row
• You can even have them in SELECT!
• And of course -my personal favorite- you can have them in subqueries
Using subqueries to filter results of set operations
• You can not attach an WHERE-clause directy to a UNION (only SELECT)
• But you can have the UNION in a FROM clause:
SELECT time
FROM (SELECT time,room FROM Lectures
UNION
SELECT time,room FROM Exercises) AS U
WHERE room='GD';