☀️

CSCC43 Summer 2021

MarkUs

Tutorial Recordings

Piazza

Calendar

CSCC43 Summer 2021

NameDateTagsWeight
MidtermIndividual & Proctored 30%
Assignment 3Group Work (3)12%
Assignment 1Group Work (2)8%
Assignment 2Group Work (3)10%

RelaX

Relax Guide by Andrew Leung

1. go to https://dbis-uibk.github.io/relax/calc/local/uibk/local/0
2. click 'Group Editor' tab to create a database
3. paste your database (make sure the formatting is correct, see employee_data base_creation.txt for an example)
4. click 'preview' button to preview your database
5. click 'use Group in editor' to now use your newly created database for your relational algebra queries (you will see on the left side that the database being used has changed)
6. click 'Relational Algebra' tab to test your queries
7. paste your query (make sure the formatting is correct, see employee_queries.txt for some examples, SPACING IS IMPORTANT)
8. click 'execute query' button to run your query

Once you run your query, you can see a tree visualization of how your query is processed against the database as well as the result of your query.

Week 2

Tutorial Slides

Example Employee DB For RelaX

group: employee_data

employee = {
emp_ID:number, person_name:string
	123,  	'Rahul'
	234	'Alex'
	456	'Emma'
	789	'Jemma'
	341	'Nida'
}
	company = {
company_name:string, rank:number
	'A'	4
	'B'	5
	'C'	6
	'D'	2
	'E'	3
}
roster = {emp_ID:number, company_name:string, salary:number, city:string
	234	'A'	12000000	'Miami'
	123	'B'	234444	'Kent'
	456	'C'	567777	'Miami'
	789	'D'	123333	'LA'
	341	'E'	345555	'San Francisco'
}

Tutorial 1 Worksheet Solutions w/ some other equivalent solutions and explanations

Notes

Keys

In general, keys is an umbrella term for defining various ways of uniquely/efficiently accessing tuples from a relation.

Q: What are Keys, Super keys, Primary-keys, Foreign keys ... etc?

https://www.guru99.com/dbms-keys.html

Q: What's the difference between a Super Key and Composite Key?

https://www.geeksforgeeks.org/difference-between-super-key-and-candidate-key/

Q: What's the difference between Primary Key and Foreign Key?

Primary Key vs Foreign Key

Key TypePrimary KeyForeign Key
PurposeUniquely identifies a row in a tableAn attribute in a table that is a primary key of another table (creating a relationship between the two tables)
Null ValuesNever accepts null valuesmay accept multiple null values
Indexing (not covered yet)Primary key is a clustered index and data in the DBMS table are physically organized in the sequence of the clustered index. A foreign key cannot automatically create an index, clustered or non-clustered. However, you can manually create an index on the foreign key.
AmountYou can only have the single Primary/Composite key in a table. You can have multiple foreign keys in a table.

Additional Notes

(Not taught in lecture)

Relational Algebra Identities

Additional Practice

Some students requested some additional practice for relational algebra so I compiled a list of worksheets found online. I cannot promise these will be helpful or these are the kinds of questions our Prof. will evaluate you on. This is not mandatory. This is not graded. This is completely optional.

Extra Relational Algebra Practice From Other Schools

Extra Relational Algebra Practice From Past CSCC43 Offerings

(Question are obtained from UTSC Old Exam Repository)

Week 3 (No Lecture Or Tutorials)

Week 4

Tutorial Slides

Tutorial 2 Worksheet Solutions w/ some other equivalent solutions and explanations

Recording

Basic Relational Algebra Operations Table

Example Student DB For RelaX

group: StudentDB

Student = {
	sID:number, surName:string, firstName:string, campus:string, email:string, cgpa:number
	99132, 'Avery', 'Marchmount', 'StG', 'avery@cs', 3.13
	98000, 'William', 'Fairgrieve', 'StG', 'will@cs', 4.00
	99999, 'Afsaneh', 'Ali', 'UTSC', 'aali@cs', 2.98
	00157, 'Leilani', 'Lakemeyer', 'UTM', 'lani@cs', 3.42
	11111, 'Homer', 'Simpson', 'StG', 'doh@gmail', 0.4
}

Course = {
	cNum:number, name:string, dept:string, breadth:boolean
	343, 'Intro to Databases', 'CSC', false
	207, 'Software Design', 'CSC', false
	148, 'Intro to Comp Sci', 'CSC', false
	263, 'Data Struct & Anal', 'CSC', false
	320, 'Intro to Visual Computing', 'CSC', false
	200, 'Intro Archaeology', 'ANT', true
	203, 'Human Biol & Evol', 'ANT', false
	150, 'Organisms in Environ', 'EEB', false
	216, 'Marine Mammal Bio', 'EEB', false
	263, 'Compar Vert Anatomy', 'EEB', false
	110, 'Narrative', 'ENG', true
	205, 'Rhetoric', 'ENG', true
	235, 'The Graphic Novel', 'ENG', true
	200, 'Environmental Change', 'ENV', false
	320, 'Natl & Intl Env Policy', 'ENV', false
	220, 'Mediaeval Society', 'HIS', true
	296, 'Black Freedom', 'HIS', true
	222, 'COBOL programming', 'CSC', false
}

Offering = {
	oID:number, cNum:number, dept:string, term:number, instructor:string
	1, 343, 'CSC', 20089, 'Horton'
	2, 343, 'CSC', 20089, 'Truta'
	3, 343, 'CSC', 20009, 'Heap'
	4, 320, 'CSC', 20089, 'Jepson'
	5, 207, 'CSC', 20089, 'Craig'
	6, 207, 'CSC', 20089, 'Gries'
	7, 148, 'CSC', 20089, 'Jepson'
	8, 148, 'CSC', 20089, 'Chechik'
	9, 263, 'CSC', 20089, 'Heap'
	11, 200, 'ANT', 20089, 'Zorich'
	12, 203, 'ANT', 20089, 'Davies'
	13, 263, 'EEB', 20089, 'Johancsik'
	14, 235, 'ENG', 20089, 'Percy'
	15, 205, 'ENG', 20089, 'Reisman'
	16, 110, 'ENG', 20089, 'Atwood'
	17, 320, 'ENV', 20089, 'Suzuki'
	18, 220, 'HIS', 20089, 'Young'
	19, 220, 'HIS', 20089, 'Dow'
}

Took = {
	sID:number, oID:number, grade:number
	99132, 1, 79
	99132, 16, 98
	99132, 31, 82
	99132, 11, 99
	99132, 14, 39
	99132, 15, 62
	99132, 34, 75
	98000, 11, 79
	
	98000, 11, 79
	98000, 1, 82
	98000, 5, 89
	98000, 6, 72
	98000, 7, 89
	98000, 8, 93
	98000, 13, 98
	98000, 16, 79
	98000, 17, 79
	98000, 22, 54
	98000, 27, 89
	98000, 31, 78
	98000, 38, 92
	98000, 39, 97
	98000, 9, 78
	
	99999, 11, 99
	99999, 1, 89
	99999, 5, 76
	99999, 6, 78
	99999, 7, 71
	99999, 8, 91
	99999, 13, 100
	99999, 16, 100
	99999, 17, 94
	99999, 22, 96
	99999, 27, 52
	99999, 31, 70
	
	00157, 1, 99
	00157, 2, 70
	00157, 14, 98
	00157, 31, 82
	00157, 21, 71
	00157, 11, 39
	00157, 34, 62
	00157, 35, 75
	00157, 3, 82
	00157, 5, 59
	00157, 6, 72
	00157, 7, 100
	00157, 28, 100
	00157, 13, 100
	00157, 26, 71
	00157, 17, 59
	
	11111, 17, 46
	11111, 14, 40
	11111, 15, 0
	11111, 16, 17
	11111, 34, 45
}

Week 5

Tutorial Notes

/*
Student (sID, surName, firstName, campus, email, cgpa)
Course (dept, cNum, name, breadth)
Offering (oID, dept, cNum, term, instructor)
Took (sID, oID, grade)

Offering [dept, cNum] ⊆ Course [dept, cNum]
Took [sID] ⊆ Student [sID]
Took [oID] ⊆ Offering [oID]
*/

-- Part 1
--------------------------------------------------

-- 1. Suppose a row occurs n times in table R and m times in table S.
-- Recall: SQL uses bag sematics. A bag is a multi-set, a set that potentially
--         contains multiple copies of the same tuple      
-- a) Using bag semantics, how many times will it occur in table 𝑅 ∪ 𝑆?
n + m
-- b) Using bag semantics, how many times will it occur in table 𝑅 ∩ 𝑆?
min(n, m)
-- c) Using bag semantics, how many times will it occur in table 𝑅 − 𝑆? 
max(n - m, 0)

-- 2. Use a set operation to find all terms when Jepson and Suzuki were both
-- teaching. Include every occurrence of a term from the result of both 
-- operands.

/*
Note: `INTERSECT` removes duplicates. `INTERSECT ALL` keeps duplicates.
*/

-- SOLUTION:
(SELECT Term FROM Offering WHERE instructor = 'Suzuki')
INTERSECT ALL
(SELECT Term FROM Offering WHERE instructor = 'Jepson');

-- OUTPUT:
term
-------
20089
20081
20081
(3 rows)

-- 3. Find the sID of students who have earned a grade of 85 or more in some
-- course, or who have passed a course taught by Atwood. Ensure that no
-- sID occurs twice in the result.

/* 
Note: UNION is a set operation so it removes duplicates.
*/

-- SOLUTION:
(SELECT sid FROM took WHERE grade >= 85)
UNION
(SELECT sid
FROM Took, Offering
WHERE Took.oid = Offering.oid AND instructor = 'Atwood' AND grade >= 50);

-- ALTERNATE SOLUTION:
SELECT DISTINCT sid
FROM Took, Offering
WHERE Took.oid = Offering.oid AND 
((instructor = 'Atwood' AND grade >= 50) OR grade >= 85);

-- OUTPUT:
	sid
-------
	 157
 98000
 99132
 99999
(4 rows)

-- 4. Find all terms when csc369 was not offered.
-- Recall: EXCEPT keyword acts like the minus operator in relational algebra

-- SOLUTION:
(SELECT term FROM Offering)
EXCEPT
(SELECT term FROM Offering WHERE dept = 'CSC' AND cNum = 369);

-- OUTPUT:
 term
-------
 20081
 20089
(2 rows)

Recording

CoursesDDL.txt

CoursesData.txt

Using PostgreSQL on Mathlab

PSQL Commands

Week 6

Tutorial Notes

/*
Student (sID, surName, firstName, campus, email, cgpa)
Course (dept, cNum, name, breadth)
Offering (oID, dept, cNum, term, instructor)
Took (sID, oID, grade)

Offering [dept, cNum] ⊆ Course [dept, cNum]
Took [sID] ⊆ Student [sID]
Took [oID] ⊆ Offering [oID]
*/

-- Part 1
--------------------------------------------------

/* CONTINUED FROM WEEK 5 */

-- 5. Make a table with two columns: oID and results. In the results column,
-- report either “high” (if that offering had an average grade of 80 or
-- higher), or “low” (if that offering had an average under 60). Offerings
-- with an average in between will not be included.
-- Hints: use a set operation. You can use the SELECT clause to put a literal 
-- value into a column. 
-- For example: SELECT ‘high’ as results ....

/*
RECALL:
In SQL, GROUP BY Clause is one of the tools to summarize or aggregate the data
series. After Grouping the data, you can filter the grouped record using HAVING
Clause. HAVING Clause returns the grouped records which match the given 
condition
*/

-- SOLUTION:
(SELECT oID, 'HIGH' AS results
FROM Took
GROUP BY oID
HAVING avg(grade) >=80)
UNION
(SELECT oID, 'LOW' as results
FROM Took
GROUP by oID
HAVING avg(grade) < 60);

-- OUTPUT:
 oid | results
-----+---------
  38 | high
  14 | low
   8 | high
   7 | high
   3 | high
  28 | high
  13 | high
  39 | high
  15 | low
   1 | high
(10 rows) 


-- Part 2
--------------------------------------------------

-- 1. Write a query to find the average grade, minimum grade, and maximum grade
-- for each offering.

-- Use aggregate funtions

-- SOLUTION:
SELECT oid, avg(grade), min(grade), max(grade)
FROM Took
GROUP BY oid;

-- OUTPUT:
 oid |          avg        | min | max
-----+---------------------+-----+-----
  31 | 78.0000000000000000 |  70 | 82
  34 | 60.6666666666666667 |  45 | 75
            . . . rows omitted
   8 | 92.0000000000000000 |  91 | 93
  11 | 79.0000000000000000 | 39  | 99
(23 rows)

-- 2. Which of these queries is legal?
-- a) (top-left)
SELECT surname, sid
FROM Student, Took
WHERE Student.sid = Took.sid
GROUP BY sid;

-- OUTPUT:
ERROR: column reference "sid" is ambiguous
LINE 1: SELECT surname, sid
                         ^
/* In line does sid refer to Student.sid or Took.sid? */

-- b) (bottom-left)
SELECT surname, Student.sid
FROM Student, Took
WHERE Student.sid = Took.sid
GROUP BY campus;

-- OUTPUT:
ERROR: column "student.surname" must appear in the GROUP BY 
clause or be used in an aggregate function

-- c) (top-right)
SELECT instructor, max(grade), count(Took.oid)
FROM Took, Offering
WHERE Took.oid = Offering.oid
GROUP BY instructor;

-- OUTPUT:
 instructor | max | count
------------+-----+-------
     Jepson | 89 | 5
       Heap | 82 | 1
           . . .
     Mendel | 75 | 3
(17 rows)

-- d) (right-bottom)
SELECT Course.dept, Course.cnum,count(oid), count(instructor)
FROM Course, Offering
WHERE Course.dept = Offering.dept and Course.cnum = Offering.cnum
GROUP BY Course.dept, Course.cnum
ORDER BY count(oid);

-- OUTPUT:
 dept | cnum | count | count
------+------+-------+-------
  ENV |  320 |     1 |     1
  CSC |  369 |     1 |     1
            . . .
  CSC |  343 |     5 |     5
(18 rows)

-- 3. Find the sid and minimum grade of each student with an average over 80.

-- SOLUTION:
SELECT SID, min(grade)
FROM Took
GROUP BY sID
HAVING AVG(grade) > 80;

-- OUTPUT:
   sid | min
-------+-----
 98000 | 54
 99999 | 52
(2 rows)

-- 4. Find the sid, surname, and average grade of each student, but keep the 
-- data only for those students who have taken at least 10 courses.

-- SOLUTION:
SELECT Student.sID, surname, avg(grade)
FROM Student, Took
WHERE Student.sID = Took.sID
GROUP BY Student.sID
HAVING count(grade) >= 10;

-- OUTPUT:
   sid |  surname   |         avg
-------+------------+---------------------
   157 | Lakemeyer  | 75.9333333333333333
 99999 | Ali        | 84.5833333333333333
 98000 | Fairgrieve | 83.2000000000000000
(3 rows)

-- 5. For each student who has passed at least 10 courses, report their sid
-- and average grade on the courses that they passed.

-- SOLUTION:
SELECT sid, AVG(grade)
FROM took
WHERE grade >= 50
GROUP BY sid
HAVING count(*) >= 10;

-- OUTPUT:
  sid  |         avg
-------+---------------------
 98000 | 83.2000000000000000
 99999 | 84.5833333333333333
   157 | 78.5714285714285714
(3 rows)

-- 6. For each student who has passed at least 10 courses, report their sid
-- and average grade on all of their courses.

-- SOLUTION:
CREATE VIEW Seniors AS
SELECT sid
FROM Took
WHERE grade >= 50
GROUP BY sid
HAVING count(*) >= 10;

SELECT Seniors.sid, AVG(grade)
FROM Seniors, Took
WHERE seniors.sid = Took.sid
GROUP BY Seniors.sid;

/*
We use a VIEW because we do want a filter applied (only passing grades count) 
when choosing which students to report on, but we don’t want that filter
applied when we compute their average grade. A single WHERE clause can't 
accomplish this.
*/

-- OUTPUT:
   sid |         avg
-------+---------------------
 98000 | 83.2000000000000000
 99999 | 84.5833333333333333
   157 | 75.9333333333333333
(3 rows)

-- 7. Which of these queries is legal?

-- a) (top-left)
SELECT dept
FROM Took, Offering
WHERE Took.oID = Offering.oID
GROUP BY dept
HAVING avg(grade) > 75;

-- OUTPUT:
 dept
------
 HIS
 CSC
 EEB
 ANT
(4 rows)

-- b) (top-right)
SELECT Took.oID, avg(grade)
FROM Took, Offering
WHERE Took.oID = Offering.oID
GROUP BY Took.oID
HAVING avg(grade) > 75;

-- OUTPUT:
 oid | avg
-----+---------------------
  31 | 78.0000000000000000
   3 | 82.0000000000000000
  28 | 91.0000000000000000
  13 | 95.6666666666666667
   9 | 78.0000000000000000
   7 | 83.0000000000000000
   1 | 87.2500000000000000
  38 | 92.0000000000000000
  39 | 97.0000000000000000
  11 | 79.0000000000000000
   8 | 92.0000000000000000
(11 rows)

-- c) (bottom-left)
SELECT Took.oID, dept, cNum,avg(grade)
FROM Took, Offering
WHERE Took.oID = Offering.oID
GROUP BY Took.oID
HAVING avg(grade) > 75;

-- OUTPUT:
ERROR: column "offering.dept" must appear in the GROUP BY
clause or be used in an aggregate function
LINE 1: SELECT Took.oID, dept, cNum, avg(grade)

/*
We cannot add `dept` & `cNum` into the SELECT clause, because according to SQL
standards, SELECT clause may contain columns mentions in the GROUP BY and
expression based on aggregate functions only.

This is because of ambiguity; the GROUP BY clause produces a single record
for each group of records. GROUP BY columns such as `Took.oID` contian the
same value for all for all records in the group and any aggregate funtion
produces the ssingle value for a group. Howeverver, `dept` & `cNum` may have
multiple values with a group - which value should SQL choose as a single value
to be related to the group? Here lies the problem of ambiguity.

Note that this problem of ambiguity is removed if we GROUP BY the primary 
key.
*/

-- d) (bottom-right)
SELECT oID, avg(grade)
FROM Took
GROUP BY sID
HAVING avg(grade) > 75;

-- OUTPUT:
ERROR: column "took.oid" must appearin the GROUP BY
clause or be used in anaggregate function
LINE 1: SELECT oID, avg(grade)


-- Week 6 
-- Part 1 (Same schema db as week 5)
--------------------------------------------------

-- 1. Which of these queries is legal?
Only a and c.
Problem with b: ERROR: syntax error at or near "distinct"

-- 2. Under what conditions could these two queries give different results?
-- If that is not possible, explain why

-- SOLUTION:
If there were two students on the same campus with the same surname, 
their surname and campus would be repeated in the result of the first query,
but not in the result of the second.

-- 3. For each student who has taken a course, report their sid and the number
-- of different departments they have taken a course in.

-- SOLUTION:
SELECT sid, count(distinct dept)
FROM Took JOIN Offering ON Took.oid = Offering.oid
GROUP BY sid;

Recording

Joins Animation

Clause Order

Side Notes

Set Schema

-- in psql
set search_path to university

-- in pgadmin
SET search_path = university

Setting up PGAdmin

Week 7 (No Tutorials)

Good luck on your midterm! 🙂

Week 8

Tutorial Notes

/*
Student (sID, surName, firstName, campus, email, cgpa)
Course (dept, cNum, name, breadth)
Offering (oID, dept, cNum, term, instructor)
Took (sID, oID, grade)

Offering [dept, cNum] ⊆ Course [dept, cNum]
Took [sID] ⊆ Student [sID]
Took [oID] ⊆ Offering [oID]
*/

-- Part 2 Subqueries
--------------------------------------------------

/* CONTINUED FROM WEEK 6 */

-- 1. What does this query do? (Recall that the || operator concatenates
-- two strings 
SELECT sid, dept || cnum as course, grade
FROM Took,
	(SELECT * 
	 FROM Offering
   WHERE instructor = 'Horton') Hoffering
WHERE Took.oid = Hoffering.oid;

-- SOLUTION:
It finds the students who took an offering taught by Horton.
Note: subqueries are often used within a FROM clause. Hoffering is the
name of the resulting subquery relation

-- OUTPUT:
	 sid | course | grade
-------+--------+-------
 99132 | CSC343 | 79
 98000 | CSC343 | 82
 98000 | CSC263 | 78
 99999 | CSC343 | 89
   157 | CSC343 | 99
(5 rows)

-- 2. What does this query do?
SELECT sid, surname
FROM Student
WHERE cgpa >
	(SELECT cgpa
	 FROM Student
	 WHERE sid = 99999);

-- SOLUTION:
Question 2 demonstrates that subqueries can be used within the WHERE clause.
It finds information about students whose cGPA is higher than student 99999
Note: the the resulting relation for the subquery only has 1 tuple. 

-- OUTPUT:
	 sid | surname
-------+------------
 99132 | Marchmount
 98000 | Fairgrieve
   157 | Lakemeyer
(3 rows)

-- 3. What does this query do?
SELECT sid, dept || cnum AS course, grade
FROM Took JOIN Offering ON Took.oid = Offering.oid
WHERE
	grade >= 80 AND
	(cnum, dept) IN (
		SELECT cnum, dept
		FROM Took JOIN Offering ON Took.oid = Offering.oid
							JOIN Student ON Took.sid = Student.sid
		WHERE surname = 'Lakemeyer');

-- SOLUTION:
It finds information about students that got an 80 or higher in a course that
some Lakemeyer took. They did not have to take the course together.


-- 4.
-- (a) Suppose we have these relations: R(a, b) and S(b, c).
-- What does this query do?

SELECT a
FROM R
WHERE b in (SELECT b FROM S);

-- SOLUTION:
It files attribute 'a' values from R whose 'b' value occurs in S

-- (b) Can we express this query without using subqueries?

-- SOLUTION: yes, we might think to join R and S
SELECT a
FROM R, S
WHERE R.b = S.b

But the 2 queries are not always equivalent. If a tuple from R connects/joins
successfully with more than one tuple from S, this new query will yeild
duplicates that the original query from part (a) did not have.


-- 5. What does this query do?
SELECT instructor
FROM Offering Off1
WHERE NOT EXISTS (
	SELECT *
	FROM Offering
	WHERE
		oid <> Off1.oid AND
		instructor = Off1.instructor );

-- SOLUTION:
It finds instructors who have exactly one offering.

-- OUTPUT:
 instructor
------------
	Truta
	Heap
	Chechik
	Davies
	Johancsik
	Reisman
	Dow
	Arv
	Miller
	Mendel
	Richler
(11 rows)


-- 6. What does this query do?
SELECT DISTINCT oid
FROM Took
WHERE EXISTS (
	SELECT *
	FROM Took t, Offering o
	WHERE
		t.oid = o.oid AND
		t.oid <> Took.oid AND
		o.dept = 'CSC' AND
		took.sid = t.sid )
ORDER BY oid;

-- SOLUTION:
It finds course offerings that include a student who has taken something
else that is a CSC course.

-- Now let us write some queries!

-- 7. For each course, that is, each department and course number combination,
-- find the instructor who has taught the most offerings of it. If there are
-- ties, include them all.
-- Report the course (eg “csc343”), instructor and the number of offerings
-- of the course by that instructor.

-- (a) First, create a view called Counts to hold, for each course, and
-- each instructor who has taught it, their number of offerings.

-- SOLUTION:
CREATE VIEW Counts AS
SELECT (dept || cNum) AS course, instructor, count(*) AS count
FROM Offering
GROUP BY (dept || cNum), instructor;

-- (b) Now solve the problem. Do not use any joins. 
-- (This will force you to use a subquery.)

SELECT course, instructor
FROM Counts
WHERE (course, count) 
	IN (
		SELECT course, max(count)
		FROM Counts
		GROUP BY course
	);

DROP VIEW Counts;


-- 8. Use EXISTS to find the surname and email address of students who have
-- never taken a CSC course.

-- SOLUTION:
SELECT sid
FROM Student s
WHERE NOT EXISTS (
	SELECT *
	FROM Took t, Offering o
	WHERE t.oid = o.oid 
	AND o.dept = 'CSC'
	AND s.sid = t.sid
);


-- 9. Use EXISTS to find every instructor who has given a grade of 100.

--SOLUTION;
SELECT DISTINCT o.instructorFROM Offering o
WHERE EXISTS (
	SELECT *
	FROM Took t
	WHERE t.oid = o.oid
	AND grade = 100
);



-- 10. Let's say that a course has level “junior” if its cNum is between 100 
-- and 299 inclusive and has level “senior" if its cNum is between 300 and 499
-- inclusive. Report the average grade, across all departments and course 
-- offerings, for all junior courses and for all senior courses. 
-- Report your answer in a table that looks like this:
   level | levelavg
---------|-----------
  junior |
  senior |
-- Each average should be an average of the individual student grades, 
-- not an average of the course averages.
CREATE VIEW LevelAverages AS(
	SELECT 'junior' AS level, AVG(t.grade) AS grade
  FROM Took t, Offering o
	WHERE t.oid = o.oid
	AND o.cNum >= 100AND o.cNum < 300GROUP BY t.oid
)
UNION ALL(
	SELECT 'senior' AS level, AVG(t.grade) AS grade
	FROM Took t, Offering o
	WHERE t.oid = o.oidAND o.cNum >= 300AND o.cNum < 500GROUP BY t.oid
);
SELECT level, AVG(grade)

Recording

Week 9

Tutorial Notes

What was covered:

Recording

Note about A2 Java Part

Week 10

Tutorial Notes

What was covered:

Recording