SQL:棘手的加入

时间:2013-05-26 13:00:07

标签: sql join

我正在为考试注册和评分构建软件:

我需要从这两个表中获取数据:

考试

|------------------------------------------------------------|           
| ExamId  |  ExamTitle  |  EducationId  |  ExamDate  |               
|------------------------------------------------------------|

ExamAttempts

|-----------------------------------------------------------------------------|
| ExamAttemptId  |  ExamId  |  StudentId  |  Grade  |  NotPresentCode  |        
|-----------------------------------------------------------------------------|
  1. 学生参加教育
  2. 教育有多项考试
  3. 学生每次考试最多可尝试6次
  4. 每次尝试都被评分或标记为不存在
  5. 如果符合以下条件,学生可以报名参加考试: - 尚未通过(2级以下) - 尚未使用所有尝试

    我想列出学生可以注册的每一项考试。

    这可能相当简单,但我无法理解它,现在我被困住了!我已经尝试了一切,但还没有把它弄好。这是我做出的更无望的尝试之一(!):

    CREATE PROCEDURE getExamsOpenForSignUp
    @EducationId int,
    @StudentId int
    AS
    SELECT ex.*
    FROM Exams ex
    LEFT JOIN (
        SELECT ExamId, COUNT(ExamId) AS NumAttempts
        FROM ExamAttempts
        WHERE StudentId = @StudentId AND grade < 2 OR grade IS NULL
        GROUP BY ExamId
    ) exGrouped ON ex.ExamId = exGrouped.ExamId
    WHERE educationid = @EducationId and exGrouped.ExamId IS NULL OR exGrouped.NumAttempts < 6;
    GO
    

    我做错了什么?请帮忙......

3 个答案:

答案 0 :(得分:1)

您需要从考试和学生的所有可能性列表开始,然后淘汰不符合要求的那些。

select driver.StudentId, driver.ExamId
from (select @StudentId as StudentId, e.ExamId
      from exams e
      where e.EducationId = @EducationId
     ) driver left outer join
     (select ea.ExamId, ea.StudentId
      from ExamAttempts ea
      group by ea.ExamId, ea.StudentId
      having max(grade) >= 2 or -- passed
             count(*) >= 6
     ) NotEligible
     on driver.ExamId = NotEligible.ExamId and
        driver.StudentId = NotEligible.StudentId
where NotEligible.ExamId is NULL 

此查询的结构非常具体。 driver表包含所有可能的组合。在这种情况下,您只有一名学生,所有考试都在“教育”中。然后左连接根据您的两个要求确定哪些符合条件。最终where选择不符合条件的不匹配项或符合条件的考试。

答案 1 :(得分:1)

检查您的SP是否有效:

Select EduExams.ExamId
from
    (select * from Exams 
     where Exams.EducationId = @EducationId) EduExams 
left outer join 
    (select * from ExamAttempts 
     where ExamAttempts.StudentId = @StudentId) StudentAttempts
on EduExams.ExamID = StudentAttempts.ExamId
group by EduExams.ExamId
having count(StudentAttempts.ExamAttemptId) < 6 
       and ((max(StudentAttempts.Grade) is null) or (max(StudentAttempts.Grade) < 2))

答案 2 :(得分:0)

好的,谢谢你们的帮助 - 非常感谢!

基于@Gordon Linoffs解决方案。这就是我最终的结果:

SELECT driver.ExamId, driver.ExamTitle
FROM (
    SELECT @StudentId AS StudentId, e.ExamId, e.ExamTitle
    FROM exams e
    WHERE e.EducationId = @EducationId
) driver 
    LEFT JOIN (
        SELECT ea.ExamId, ea.StudentId
        FROM ExamAttempts ea
        WHERE ea.studentId = @StudentId
        GROUP BY ea.ExamId, ea.StudentId
        HAVING MAX(grade) >= 2 OR COUNT(*) >= 6
    ) NotEligible
        ON driver.ExamId = NotEligible.ExamId AND driver.StudentId = NotEligible.StudentId
WHERE NotEligible.ExamId IS NULL