You could start by creating a query that selects the students that had insufficient for the last exam, with a count on how many they failed in total, and which was their first exam that they failed:
SELECT StudentID,
Count(*) AS FailCount,
Max(ExamCode) AS LastExamCode,
Min(ExamCode) AS FirstExamCode
FROM [Exam Scores]
WHERE Score <= 69
GROUP BY StudentID
HAVING Max(ExamCode) = (SELECT Max(ExamCode) FROM [Exam Dates])
Save the above SQL
as a query with name FailingStudents
From this query you could then take the records with FailCount = 2
for the first report, and = 3
for the second.
For the first report you will also have out-of-the-box the codes of the two exams concerned. With that you can retrieve the Book, Version and Score by joining [Exam Scores] again for each of them.
For the second report it is bit more tricky: you have 2 out of the three exam codes, but you can join [Exam Scores] for the middle one by requiring that its ExamCode is between (and not equal to) the two extremes.
Here is an SQL
for the first report, using the query made above:
SELECT Students.StudentName,
Students.StudentID,
FirstFail.ExamCode,
FirstFail.Book,
FirstFail.Version,
FirstFail.Score,
LastFail.ExamCode,
LastFail.Book,
LastFail.Version,
LastFail.Score
FROM (((FailingStudents
INNER JOIN Students
ON Students.StudentID = FailingStudents.StudentID)
INNER JOIN [Exam Scores] LastFail
ON LastFail.ExamCode = FailingStudents.LastExamCode
AND LastFail.StudentID = FailingStudents.StudentID)
INNER JOIN [Exam Scores] FirstFail
ON FirstFail.ExamCode = FailingStudents.FirstExamCode
AND FirstFail.StudentID = FailingStudents.StudentID)
WHERE FailingStudents.FailCount = 2;
Note however, that with the data you provided in comments, there are no matching records.
The second report could be based on an extension of the previous SQL
, like this:
SELECT Students.StudentName,
Students.StudentID,
FirstFail.ExamCode,
FirstFail.Book,
FirstFail.Version,
FirstFail.Score,
SecondFail.ExamCode,
SecondFail.Book,
SecondFail.Version,
SecondFail.Score,
LastFail.ExamCode,
LastFail.Book,
LastFail.Version,
LastFail.Score
FROM ((((FailingStudents
INNER JOIN Students
ON Students.StudentID = FailingStudents.StudentID)
INNER JOIN [Exam Scores] LastFail
ON LastFail.ExamCode = FailingStudents.LastExamCode
AND LastFail.StudentID = FailingStudents.StudentID)
INNER JOIN [Exam Scores] FirstFail
ON FirstFail.ExamCode = FailingStudents.FirstExamCode
AND FirstFail.StudentID = FailingStudents.StudentID)
INNER JOIN [Exam Scores] SecondFail
ON SecondFail.ExamCode < FailingStudents.LastExamCode
AND SecondFail.ExamCode > FailingStudents.FirstExamCode
AND SecondFail.StudentID = FailingStudents.StudentID)
WHERE FailingStudents.FailCount = 3;
Note the extra JOIN
and the 3
at the end.
This query returns two instances based on the data you provided:
You can see this in this fiddle, which is based on MySQL
, but it is the same principle.