2011-06-24 104 views
2

这是我的问题(我正在使用SQL Server)SQL - 从多个表中选择计数

我有一个表Students (StudentId, Firstname, Lastname, etc)

我有记录StudentAttendance (StudentId, ClassDate, etc.)

我记录其他学生活动(我在这里概括为简单起见),如表Papers一个(StudentId, PaperId, etc.)表。可能有从0到20个文件转入的任何地方。同样,有一个表Projects (StudentId, ProjectId, etc.)。与Papers相同。

我想要做的是为参加超过一定水平的学生(例如10名出勤)创建一个计数列表。事情是这样的:

ID Name  Att Paper Proj 
123 Baker  23  0  2 
234 Charlie 26  5  3 
345 Delta  13  3  0 

以下是我有:

select 
    s.StudentId, 
    s.Lastname, 
    COUNT(sa.StudentId) as CountofAttendance, 
    COUNT(p.StudentId) as CountofPapers 
from Student s 
inner join StudentAttendance sa on (s.StudentId = sa.StudentId) 
left outer join Paper p on (s.StudentId = p.StudentId) 
group by s.StudentId, s.Lastname 
Having COUNT(sa.StudentId) > 10 
order by CountofAttendance 

如果CountofPaper和join(无论是内部或左外)的Papers表被注释掉,查询工作正常。我收到了至少参加过10节课的学生。

但是,如果我把CountofPapers和加入,事情变得疯狂。通过左外连接,任何有论文的学生只会在论文栏中显示出席人数。通过内部联合,出勤率和纸张计数似乎可以相互叠加。

指导需要和赞赏。

戴夫

回答

0

问题是有多个papers每个学生,所以StudentAttendance一行的Paper每一行加入:计数将被重新添加每次。试试这个:

select 
    s.StudentId, 
    s.Lastname, 
    (select COUNT(*) from StudentAttendance where s.StudentId = sa.StudentId) as CountofAttendance, 
    (select COUNT(*) from Paper where s.StudentId = p.StudentId) as CountofPapers 
from Student s 
where (select COUNT(*) from StudentAttendance where s.StudentId = sa.StudentId) > 10 
order by CountofAttendance 

编辑过参考合并问题CountofAttendance

顺便说一句,这不是最快的解决方案,但它是最容易理解的,这是我的本意。您可以通过使用加入别名选择来避免重新计算,但正如我所说的,这是最简单的。

+0

谢谢billinkc,波西米亚和亚历克斯Aza伟大的答案。我非常感谢你们每个人花时间制定解决方案的时间。我将把波希米亚的标记作为答案,但我认为每个解决方案都能奏效。我在答案中遇到的唯一问题是波希米亚,因为某些原因,“使用CountofAttendance> 10”的情况下,SSMS不认为它是一列。我最终复制了“as CountofAttendance”中的选择,并且查询起作用(无效,毫无疑问)。 CountAttendance的顺序很好,这是很奇怪的部分。也感谢marc_s的编辑。最好,戴夫 – Dave

0

试试这个:

select std.StudentId, std.Lastname, att.AttCount, pap.PaperCount, prj.ProjCount 
from Students std 
    left join 
    (
     select StudentId, count(*) AttCount 
     from StudentAttendance 
    ) att on 
     std.StudentId = att.StudentId 
    left join 
    (
     select StudentId, count(*) PaperCount 
     from Papers 
    ) pap on 
     std.StudentId = pap.StudentId 
    left join 
    (
     select StudentId, count(*) ProjCount 
     from Projects 
    ) prj on 
     std.StudentId = prj.StudentId 
where att.AttCount > 10 
+0

感谢解决方案亚历克斯 – Dave

1

看看使用Common Table Expressions,然后分而治之,解决您的问题。顺便说一句,你是关闭的1原始查询,您将有11最低勤

; 
WITH GOOD_STUDENTS AS 
(
-- this query defines all students with 10+ attendance 
SELECT 
    S.StudentID 
, count(1) AS attendence_count 
FROM 
    Student S 
    inner join 
    StudentAttendance sa 
    on (s.StudentId = sa.StudentId) 
GROUP BY 
    S.StudentId 
HAVING 
    COUNT(1) >= 10 
) 
, STUDIOUS_STUDENTS AS 
(
-- lather, rinse, repeat for other metrics 
SELECT 
    S.StudentID 
, count(1) AS paper_count 
FROM 
    Student S 
    inner join 
    Papers P 
    on (s.StudentId = P.StudentId) 
GROUP BY 
    S.StudentId 
) 
, GREGARIOUS_STUDENTS AS 
(
SELECT 
    S.StudentID 
, count(1) AS project_count 
FROM 
    Student S 
    inner join 
    Projects P 
    on (s.StudentId = P.StudentId) 
GROUP BY 
    S.StudentId 
) 
-- And now we roll it all together 
SELECT 
    S.* 
, G.attendance_count 
, SS.paper_count 
, GS.project_count 
-- ad nauseum 
FROM 
    -- back to the well on this one as there may be 
    -- students did nothing 
    Students S 
    LEFT OUTER JOIN 
     GOOD_STUDENTS G 
     ON G.studentId = S.studentId 
    LEFT OUTER JOIN 
     STUDIOUS_STUDENTS SS 
     ON SS.studentId = S.studentId 
    LEFT OUTER JOIN 
     GREGARIOUS_STUDENTS GS 
     ON GS.studentId = S.studentId 

我看到很多其他的答案滚滚而来,但我打的时间太长了退出;)

+0

谢谢你在比尔的时间。戴夫 – Dave