鉴于表格:
Exam (ExamId, SubjectId)
Result (ExamId, StudentId, GradeId)
检索在SubjectId ='数学'中获得GradeId ='A'并且在SubjectId ='English'中获得GradeId ='A'的学生列表的最佳方法是什么,以获取每个科目的最近一次考试?我们可以假设ExamIds随着时间的推移而增加,或者将ExamDate列添加到Exam。
谢谢!
答案 0 :(得分:3)
您需要做的第一件事是处理“最近的考试”条件。
以下内容按主题获取每位学生的最新考试...
SELECT
[Result].StudentID,
[Exam].SubjectID,
MAX([Exam].id) AS ExamID
FROM
Result
INNER JOIN
Exam
ON [Exam].id = [Result].ExamID
GROUP BY
[Result].StudentID,
[Exam].SubjectID
然后,您需要获得每个考试的成绩,并应用您的限制......
SELECT
[Recent].StudentID
FROM
(
SELECT
[Result].StudentID,
[Exam].SubjectID,
MAX([Exam].id) AS ExamID
FROM
Result
INNER JOIN
Exam
ON [Exam].id = [Result].ExamID
GROUP BY
[Result].StudentID,
[Exam].SubjectID
)
AS [Recent]
INNER JOIN
Result
ON [Result].StudentID = [Recent].StudentID
AND [Result].ExamID = [Recent].ExamID
GROUP BY
[Recent].StudentID
HAVING
MIN(
CASE [Exam].SubjectID
WHEN 'Maths' THEN CASE WHEN GradeID = 'A' THEN 1 ELSE 0 END
WHEN 'English' THEN CASE WHEN GradeID = 'B' THEN 1 ELSE 0 END
ELSE 1
END
)
= 1
如果您知道您只想要MATHS和ENGLISH,可以通过在[Recent]的子查询中添加WHERE子句来加速...
WHERE
[Exam].Subject IN ('Maths', 'English')
编辑:
查询的“MIN(CASE)= 1”部分如下工作...
- 如果主题是数学,并且他们得到A,那么1.否则为0.
- 如果主题是英语,并且他们得到B,那么1.否则为0.
- 如果主题是其他任何内容,那么1.
如果其中任何一项返回0,请忽略该学生。
因此,如果学生有数学:A,英语:B,地理:A,地理不会导致0,所以不会导致学生被忽略,无论他们的地理等级如何。
现在考虑更多,如果他们没有数学和/或英语成绩,他们仍然可以通过这项检查。如果您想排除未参加数学和/或英语测试的学生,请改用此HAVING子句......
SUM(
CASE [Exam].SubjectID
WHEN 'Maths' THEN CASE WHEN GradeID = 'A' THEN 1 ELSE 0 END
WHEN 'English' THEN CASE WHEN GradeID = 'B' THEN 1 ELSE 0 END
ELSE 0
END
)
= 2
ELSE 0确保忽略其他主题,SUM()= 2确保两个条件匹配。
编辑:
将要求放在表格中(并加速一切)......
DECLARE @requirements TABLE (
SubjectID NVARCHAR(32),
GradeID NCHAR(1)
)
INSERT INTO @requirements VALUES (N'Maths', N'A')
INSERT INTO @requirements VALUES (N'English', N'B')
SELECT
[Recent].StudentID
FROM
(
SELECT
[Result].StudentID AS [StudentID],
[Exam].SubjectID AS [SubjectID],
MAX([Exam].id) AS [ExamID],
[Requirements].GradeID AS [RequiredGrade]
FROM
Exam
INNER JOIN
@requirements [Requirements]
ON [Requirements].SubjectID = [Exam].SubjectID
INNER JOIN
Result
ON [Exam].id = [Result].ExamID
GROUP BY
[Result].StudentID,
[Exam].SubjectID,
[Requirements].GradeID AS RequiredGrade
)
AS [StudentExam]
INNER JOIN
Result
ON [Result].StudentID = [StudentExam].StudentID
AND [Result].ExamID = [StudentExam].ExamID
AND [Result].GradeID = [StudentExam].RequiredGrade
GROUP BY
[Recent].StudentID
HAVING
COUNT(*) = (SELECT COUNT(*) FROM @requirements)
正如另一篇文章所述,如果你可以在那里获得ExamDate,那将比ExamID列更可靠。还应该说,只要您对数据库有足够的控制权,就应该能够阻止身份值做除了前进之外的任何事情。
答案 1 :(得分:0)
如果你从这篇文章中得不到任何其他内容,那就让它成为:不要以为ID会一直增加。这只会导致黑暗面。投入考试日期(我不知道为什么你不会有一个,除非你的教授忘了把它放在作业问题中)并用它来确定考试是在考试之前还是之后。
那就是说,这里有两种可能的方法。两者都没有经过测试,所以你应该测试它们,并确保你完全理解这些解决方案。毕竟他们可能正在参加考试。 :)
SELECT
ENG.StudentID
FROM
Results ENG_RES
INNER JOIN Exams ENG_EX ON
ENG_EX.ExamID = ENG_RES.ExamID AND
ENG_EX.SubjectID = 'English'
INNER JOIN Results MATH_RES ON
MATH_RES.StudentID = ENG_RES.StudentID AND
MATH_RES.GradeID = 'A'
INNER JOIN Exams MATH_EX
MATH_EX.ExamID = MATH_RES.ExamID AND
MATH_EX.SubjectID = 'Math'
LEFT OUTER JOIN Results MATH_RES2 ON
MATH_RES2.StudentID = ENG_RES.StudentID
LEFT OUTER JOIN Exams MATH_EX2
MATH_EX2.ExamID = MATH_RES2.ExamID AND
MATH_EX2.SubjectID = 'Math' AND
MATH_EX2.ExamDate > MATH_EX.ExamDate
LEFT OUTER JOIN Results ENG_RES2 ON
ENG_RES2.StudentID = ENG_RES.StudentID
LEFT OUTER JOIN Exams ENG_EX2
ENG_EX2.ExamID = ENG_RES2.ExamID AND
ENG_EX2.SubjectID = 'English' AND
ENG_EX2.ExamDate > ENG_EX.ExamDate
WHERE
ENG_RES.GradeID = 'B' AND
MATH_EX2.ExamID IS NULL AND
ENG_EX2.ExamID IS NULL
或者:
SELECT
ENG.StudentID
FROM
Results ENG_RES
INNER JOIN Exams ENG_EX ON
ENG_EX.ExamID = ENG_RES.ExamID AND
ENG_EX.SubjectID = 'English'
INNER JOIN Results MATH_RES ON
MATH_RES.StudentID = ENG_RES.StudentID AND
MATH_RES.GradeID = 'A'
INNER JOIN Exams MATH_EX
MATH_EX.ExamID = MATH_RES.ExamID AND
MATH_EX.SubjectID = 'Math'
WHERE
ENG_RES.GradeID = 'B' AND
NOT EXISTS
(
SELECT *
FROM
Results SQR1
INNER JOIN Exams SQE1 ON
SQE1.ExamID = SQR1.ExamID AND
SQE1.SubjectID = 'Math' AND
SQE1.ExamDate > MATH_EX.ExamDate
WHERE
SQR1.StudentID = ENG_RES.StudentID
) AND
NOT EXISTS
(
SELECT *
FROM
Results SQR2
INNER JOIN Exams SQE2 ON
SQE2.ExamID = SQR2.ExamID AND
SQE2.SubjectID = 'English' AND
SQE2.ExamDate > ENG_EX.ExamDate
WHERE
SQR2.StudentID = ENG_RES.StudentID
)