2.15 Finding the Complement of a Missing Set2.15.1 ProblemThe query in the previous recipe has one significant drawback: it does not report missing term papers for students who have not yet completed at least one term paper. That's because the driving table is the Students table. If a student hasn't handed in at least one term paper for a course, then there won't be any records in the Students table for that student/course combination. How then, do you report missing term papers for such students? 2.15.2 SolutionThe key to reporting missing term papers for students who have not yet turned in any term papers is to find a reliable way to identify those students. There are two possibilities:
From a database-design perspective, the second solution is probably the best, because you end up with a typical many-to-one relationship between two tables. The first solution is something of a kludge , because it uses the Students table as both a master table and as a detail table. 2.15.2.1 Solution 1: Define empty rows in the Students tableOur first solution calls for empty records to be inserted into the Students table for each student/course combination. For example, the following record would be inserted to show that David was enrolled in the ACCN101 course: INSERT INTO Students(CourseId, StudentName, Score, TermPaper) VALUES('ACCN101','David',0,0) Notice that the Score and term paper number have both been set to 0. With these records in place, the query presented in the previous recipe can be used to display the list of missing term papers. This list will now include cases where a student has missed all term papers in a given course. The zero-records that we've inserted won't show in the final result because our query excludes the Pivot table row for zero. 2.15.2.2 Solution 2: Create a student master tableA cleaner option than creating special zero-records in the Students table is to create a completely separate student master table. This table would then track each students's enrollment in the various courses offered by the university. The following shows one possible implementation: CREATE TABLE StudentMaster( CourseId CHAR(20), StudentName CHAR(40) ) INSERT INTO StudentMaster VALUES('ACCN101','Andrew') INSERT INTO StudentMaster VALUES('MGMT120','Andrew') INSERT INTO StudentMaster VALUES('ACCN101','Bert') INSERT INTO StudentMaster VALUES('ACCN101','Cindy') INSERT INTO StudentMaster VALUES('MGMT120','Cindy') INSERT INTO StudentMaster VALUES('ACCN101','David') With the StudentMaster table in place and populated as shown, you can generate a report of missing term papers using the following query: SELECT s.StudentName, s.CourseId, f.i TermPaper FROM StudentMaster s, Pivot f WHERE f.i BETWEEN 1 AND 4 GROUP BY s.StudentName, s.CourseId, f.i HAVING NOT EXISTS( SELECT * FROM Students WHERE CourseId=s.CourseId AND StudentName=s.StudentName AND TermPaper=f.i) ORDER BY s.StudentName The report lists the missing term papers for each student: StudentName CourseId TermPaper ------------- -------------------- ----------- Andrew ACCN101 1 Andrew MGMT120 4 Bert ACCN101 4 Cindy ACCN101 3 Cindy ACCN101 4 Cindy MGMT120 4 David ACCN101 1 David ACCN101 2 David ACCN101 3 David ACCN101 4 2.15.3 DiscussionIf you think about it, both solutions in this recipe require the creation of a master table for students and courses. In the first solution, that master table is layered onto the existing Students table, while, in the second solution, the master table is a completely separate table named StudentMaster. The query shown for Solution 2 uses the StudentMaster table as the basis for preparing a list of groups that need to be considered . Each group represents one student and course combination. The master table is joined to the Pivot table, and the result is a complete list of all required term papers for all student/course combinations. The HAVING clause checks the Students table to see what papers have been submitted and reduces the result of the main query to only the term papers. |