Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ssh/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server SQL Server:迭代一个表的行,同时比较两个其他表的结果集_Sql Server_Tsql - Fatal编程技术网

Sql server SQL Server:迭代一个表的行,同时比较两个其他表的结果集

Sql server SQL Server:迭代一个表的行,同时比较两个其他表的结果集,sql-server,tsql,Sql Server,Tsql,我有3张桌子,看起来像这样 学生 studentID studentName 1 John 2 Jack 3 Jane 科目 subjectID subjectName 1 maths 2 geography 3 history 4 physics 演出 studentID subject_passed mark_o

我有3张桌子,看起来像这样

学生

studentID    studentName
1            John
2            Jack
3            Jane
科目

subjectID    subjectName
1            maths
2            geography
3            history
4            physics
演出

studentID    subject_passed    mark_obtained
1            maths             40
2            physics           50
1            geography         40 
3            maths             80
1            physics           40
2            maths             70
2            geography         40
1            history           30
使用上面的例子,我想做的是选择所有通过所有科目且总分超过120分的学生

这就是我迄今为止所尝试的

  • 使用游标(和while循环)在studentId上迭代,然后使用EXCEPT查找两个结果集之间的差异,如下所示
  • 我在这种方法中遇到了两个挑战; 它返回n个(学生数)不同的结果集 考虑到WHERE子句中不允许使用聚合函数,我也不知道如何合并关于和的第二个条件

  • 我还尝试将“所有科目”选入一个列表,将“学生通过的所有科目”选入另一个列表,并像这样进行比较;
    select student from student where(选择string_agg(所有科目))=(选择string_agg(学生传递的科目))
    但我仍然遇到了同样的挑战,那就是未能将求和的第二个条件融入到整个事物组合中
  • 要求是选择通过所有科目且总分超过120分的学生。
    我很感激您能为我提供指导。

    使用
    交叉连接
    获取每个学生和每个科目的列表,然后
    左连接
    到表
    绩效
    。然后,您可以使用
    HAVING
    子句筛选出那些通过所有科目考试、总分超过120分的学生。我用条件计数筛选出那些没有通过所有测试的行,其中我只计算表
    Performance
    mark\u获得的
    值为
    NULL
    的行(我假设只有当学生/科目没有行时才会发生这种情况)

    这是一种比使用
    光标
    好得多的方法。SQLServerExcels是基于集合的方法,而不是迭代的方法,游标落在后者中

    使用,可以在单独的子查询中收集每个学生的统计信息:

    WITH StatisticsPerStudent AS
    (   SELECT studentId,
                COUNT(1) AS TotalSubjectsPassed,
                SUM(mark_obtained) AS TotalMarks
        FROM Performance
        GROUP BY studentId
    ) SELECT *
        FROM Students
            JOIN StatisticsPerStudent ON StatisticsPerStudent.studentId = Students.studentId
      WHERE 
            StatisticsPerStudent.TotalSubjectsPassed = (SELECT COUNT(1) FROM Subjects) --passed all subjects
            AND StatisticsPerStudent.TotalMarks > 120  --total marks exceeding 120
    

    通过该科目的标准是什么?我的意思是最低分数,这是一个非常好的问题。您提供了示例数据,并展示了您迄今为止的尝试。我唯一有建设性的批评是,最好能把期望的结果说清楚,而不是仅仅描述出来。太好了!这就是它-不可能想到这样做。非常感谢!旁白:CTE不是在创建临时表的离散步骤中执行的,它是由查询优化器处理的,查询优化器可能会生成一个执行计划,将所有步骤合并到一个查询中。@HABO,感谢您的评论,我已通过删除临时表修复了我的答案table@Renat谢谢你的解决方案。该方法很好,易于遵循。
    CREATE TABLE dbo.Student (StudentID int, StudentName varchar(5));
    INSERT INTO dbo.Student (StudentID,
                             StudentName)
    VALUES(1,'John'),
          (2,'Jack'),
          (3,'Jane');
    
    CREATE TABLE dbo.Subject (SubjectID int, SubjectName varchar(10));
    INSERT INTO dbo.Subject (SubjectID,
                             SubjectName)
    VALUES(1,'maths'),
          (2,'geography'),
          (3,'history'),
          (4,'physics');
    
    CREATE TABLE dbo.Performance (StudentID int, subject_passed varchar(10), mark_obtained int);
    INSERT INTO dbo.Performance (StudentID,
                                 subject_passed,
                                 mark_obtained)
    VALUES (1,'maths',40),
           (2,'physics',50),
           (1,'geography',40),
           (3,'maths',80),
           (1,'physics',40),
           (2,'maths',70),
           (2,'geography',40),
           (1,'history',30);
    
    GO
    
    SELECT St.StudentID,
           St.StudentName,
           SUM(P.mark_obtained) AS Marks_obtained
    FROM dbo.Student St
         CROSS JOIN dbo.Subject Su
         LEFT JOIN dbo.Performance P ON St.StudentID = P.StudentID
                                    AND Su.SubjectName = P.subject_passed --This should really be ID
    GROUP BY St.StudentID,
             St.StudentName
    HAVING COUNT(CASE WHEN P.mark_obtained IS NULL THEN 1 END) = 0
       AND SUM(P.mark_obtained) > 120
    
    GO
    
    DROP TABLE dbo.Performance;
    DROP TABLE dbo.Subject;
    DROP TABLE dbo.Student;
    
    WITH StatisticsPerStudent AS
    (   SELECT studentId,
                COUNT(1) AS TotalSubjectsPassed,
                SUM(mark_obtained) AS TotalMarks
        FROM Performance
        GROUP BY studentId
    ) SELECT *
        FROM Students
            JOIN StatisticsPerStudent ON StatisticsPerStudent.studentId = Students.studentId
      WHERE 
            StatisticsPerStudent.TotalSubjectsPassed = (SELECT COUNT(1) FROM Subjects) --passed all subjects
            AND StatisticsPerStudent.TotalMarks > 120  --total marks exceeding 120