T-SQL,在视图中重复相同的标量子查询性能

T-SQL, repeated same scalar subquery performance in views

下面是一个简单的查询,用于检索学生及其考试成绩。同一个学生可以多次参加同一个考试。子查询检索每个学生的最新考试成绩。如您所见,X 行(检索最新的考试 ID)在每一行的每个子查询中完全相同。如何存储或缓存X行的结果以防止每行执行三次? 我不能为此任务使用存储过程或函数,它必须是一个 VIEW 以进行额外的过滤。

SELECT S.*,
(
  SELECT COUNT(*) FROM ExamAnswers WHERE 
  IsCorrectAnswer IS NOT NULL AND
  IsCorrectAnswer = 1 AND 
  ExamID = 
  (SELECT TOP(1) ID FROM Exams E WHERE E.StudentID = S.ID ORDER BY ID DESC) --Line X
) CorrectAnswerCount,
(
  SELECT COUNT(*) FROM ExamAnswers EA WHERE 
  EA.IsCorrectAnswer IS NOT NULL AND
  EA.IsCorrectAnswer = 0 AND 
  EA.ExamID = 
  (SELECT TOP(1) ID FROM Exams E WHERE E.StudentID = S.ID ORDER BY ID DESC) --Line X
) WrongAnswerCount,
(
  SELECT COUNT(*) FROM ExamAnswers WHERE 
  IsCorrectAnswer IS NULL AND
  ExamID = 
  (SELECT TOP(1) ID FROM Exams E WHERE E.StudentID = S.ID ORDER BY ID DESC) --Line X
) UnansweredQuestionCount

FROM Students S

你可以这样做

SELECT S.*,
       CA.*
FROM   Students S
       CROSS APPLY (SELECT SUM(CASE WHEN IsCorrectAnswer = 1 THEN 1 ELSE 0 END) AS CorrectAnswerCount,
                           SUM(CASE WHEN IsCorrectAnswer = 0 THEN 1 ELSE 0 END) AS WrongAnswerCount,
                           SUM(CASE WHEN IsCorrectAnswer IS NULL THEN 1 ELSE 0 END) AS UnansweredQuestionCount
                    FROM   ExamAnswers EA
                    WHERE  EA.ExamID = (SELECT TOP(1) ID
                                        FROM   Exams E
                                        WHERE  E.StudentID = S.ID
                                        ORDER  BY ID DESC)) CA 

这种方法怎么样:

WITH
T AS
(
SELECT Student_id,
       SUM(CASE IsCorrectAnswer WHEN 1 THEN 1 END) AS COUNT_TRUE,
       SUM(CASE IsCorrectAnswer WHEN 0 THEN 1 END) AS COUNT_FALSE,
       SUM(CASE WHEN IsCorrectAnswer IS NULL THEN 1 END) AS COUNT_UNKNOWN
FROM   ExamAnswers AS EA 
WHERE  EA.ExamID = (SELECT MAX(ID) 
                    FROM   Exams E 
                    WHERE  E.StudentID = S.ID)
GROUP  BY Student_id
)
SELECT S.*, COUNT_TRUE, COUNT_FALSE, COUNT_UNKNOWN
FROM   Students AS S
       JOIN T ON S.ID = T.Student_id