FINAL SOLUTIONS
CS122, Spring 2004




[Normalization] Suppose a student registration database has a table Grades for student grades:

Grades: <studentID, lastName, firstName, courseId, courseTitle, sectionNumber, semester, year, units, meetingTime, meetingRoom, grade>

Assumptions:
1. (15pt) What are the key(s) of the table? If there are more than one key in the table, choose one of them as your primary key, and list all partial dependencies and transitive dependencies.
Assumption A. a student can repeat a course (in a different semester, of course)

Primary Key: (studentID, courseID, semester, year)

Partial Dependencies:
Transitive Dependencies:
None.

The only possible transitive dependency is (courseTitle) -> (units), and whether it is indeed one depends on the answer to the question "can two courses have the same title but different units?". My answer to this question is yes, for example, we may have two different courses both called "Introduction to Programming", while one of them is for CS majors and 4 units, and the other one is for non-CS majors and 2 units. Therefore, units does not transitively depend on courseTitle.

Note that if you do assume that courseTitle is unique and (couseTitle) -> (unit), then you must also have (courseTitle) -> (courseID), as well as (studentID, courseTitle, semester, year) being another key.
Assumption B. a student cannot repeat a course

Primary Key: (studentID, courseID)

Partial Dependencies:
Transitive Dependencies:
None.
2. (10pt) Normalize the table to 2NF. The answers to this question and the next question should be in the form:
Interestingly enough, in both cases we'll end up with the same tables:
Students: <studentID, lastName, firstName>, primary key (studentID)
Courses: <courseID, courseTitle, units>, primary key (courseID)
Grades: <studentID, courseID, sectionNumber, semester, year, meetingTime, meetingRoom, grade>
3. (10pt) Normalize the table to 3NF.
Since there are no transitive dependencies, the 2NF tables are already 3NF. On the other hand, we do note that meetingTime and meetingRoom seem to be out of place in the Grades table, and indeed they are, because we have another dependency:
(courseID, sectionNumber, semester, year) -> (meetingtime, meetingRoom)
By definition this dependency is neither a partial dependency nor a transitive dependency, so although intuitively the Grades table is not properly designed, it is still 3NF, which is a good example showing the need for 4NF.

4. (15pt) Write CREATE TABLE statements for the 3NF tables with proper primary key and foreign key constraints.
Omitted.

Use Lyric2K.mdb for the following questions:

[Queries]

5. (5pt) Use a correlated subquery to list all genres that do not have recorded titles.
SELECT g.Genre FROM Genre g WHERE NOT EXISTS (SELECT 1 FROM Titles t WHERE t.Genre = g.Genre);
6. (5pt) Produces a single list of studio names with their web addresses and artist names with their web addresses. Do not include any studio or artist who does not have a web address. For example:
SELECT studioName as [name], webAddress FROM Studios WHERE webAddress IS NOT NULL AND LEN(TRIM(webAddress)) <> 0;
UNION
SELECT artistName, webAddress FROM Artists WHERE webAddress IS NOT NULL AND LEN(TRIM(webAddress)) <> 0;
7. (10pt) List each genre from the genre table and the total length in minutes of all tracks recorded for that genre. If a genre does not have a recorded title, or the in the case of pop, the information about the track lengths is not available in the database, list the recorded length for that genre as 0. Use proper column headings.

The difficulty of this problem is not coming up with a query, but the fact that MS Access does not support nesting LEFT JOIN with INNER JOIN, e.g. you'll get a syntax error if you replace the first "INNER JOIN" in the following query with "LEFT JOIN". A walkaround for this is to use  nested INNER JOINs to get the genres that have recorded tracks, and union the results with the genres that do not.
SELECT g.Genre, SUM(t2.LengthSeconds)/60 AS [Recorded Length in Minutes] FROM Genre g INNER JOIN (Titles t1 INNER JOIN Tracks t2 ON t1.TitleID = t2.TitleID)  ON g.Genre = t1.Genre GROUP BY g.Genre
UNION
SELECT g.Genre, 0 FROM Genre g WHERE NOT EXISTS (SELECT 1 FROM Titles t1, Tracks t2 WHERE g.Genre = t1.Genre AND t1.TitleID = t2.TitleID);
8. (5pt) List the names of all salespersons whose supervisor is supervised by no one.
SELECT s1.FirstName+' '+s1.LastName FROM SalesPeople s1, SalesPeople s2 WHERE s1.SuperVisor = s2.SalesID and s2.Supervisor IS NULL;
9. (5p) Each member is given his or her salesperson as a primary contact name and also the name of that salesperon's supervisor as a secondary contact name. Produce a list of member names and the primary and secondary contacts for each member.
SELECT m.FirstName + " " + m.LastName AS [Member], s1.FirstName + " " + s1.LastName as [Primary Contact], s2.FirstName + " " + s2.LastName as [Secondary Contact] FROM Members m, SalesPeople s1, SalesPeople s2 WHERE m.SalesID = s1.SalesID AND s1.Supervisor = s2.SalesID;

[Updates]

10. (5pt) Add a new artist to the Artists table with the following information:
ArtistID ArtistName
City
Region
Country
WebAddress
EntryDate
LeadSource
12
November
New Orleans
LA
USA

(today)
Directmail
Use a database function to get today's date.

INSERT INTO Artists (ArtistID, ArtistName, City, Region, Country, EntryDate, LeadSource) VALUES (12, 'November', 'New Orleans', 'LA', 'USA', DATE(), 'Directmail');

11. (5pt) Lyric Music has decided to set up a web page for every artist who does not have a web site. The web address will be www.lyricmusic.com/ followed by the artist ID. Update the Artists table accordingly.
My bad on this one. I thought ArtistID was a text field and the query would be just like the one we did before with author emails, but it turns out that ArtistID is a numerical field which has to be converted to string using the STR function. Since we did not cover STR in class, everybody gets 5pt for this one.
UPDATE Artists SET WebAddress = 'www.lyricmusic.com/'+TRIM(STR(ArtistID)) WHERE WebAddress LIKE 'www.lyricmusic*';
12. (10pt) Due to some contract disputes, Lyric Music must remove all MP3 and Real Audio downloads for the tracks from the title Time Flies. Update the Tracks table accordingly.
Note that removing MP3 and Real Audio downloads for Times Flies does not  mean removing all  information about the tracks, and it certainly does not mean drop the MP3 and ReadAud columns in the Tracks table.

UPDATE Tracks SET MP3=NO, RealAud=NO WHERE TitleID = (SELECT TitleID FROM Titles WHERE Title = 'Time Flies');