Sql server SQL Server:迭代一个表的行,同时比较两个其他表的结果集
我有3张桌子,看起来像这样 学生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
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分的学生
这就是我迄今为止所尝试的
select student from student where(选择string_agg(所有科目))=(选择string_agg(学生传递的科目))
但我仍然遇到了同样的挑战,那就是未能将求和的第二个条件融入到整个事物组合中我很感激您能为我提供指导。使用
交叉连接
获取每个学生和每个科目的列表,然后左连接
到表绩效
。然后,您可以使用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