SQL - 从多个表中选择计数

时间:2011-06-24 03:30:37

标签: sql-server count

这是我的问题(我正在使用SQL Server)

我有一张Students (StudentId, Firstname, Lastname, etc)的表格。

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

的表格

我记录了其他学生活动(为了简单起见,我在这里概括),例如Papers(StudentId, PaperId, etc.)。可能有零到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

如果注释掉CountofPaperPapers表的连接(内部或左外部),则查询工作正常。我得到了很多参加过至少10门课程的学生。

然而,如果我加入CountofPapers和加入,事情会变得疯狂。通过左外连接,任何有论文的学生只会在论文栏中显示他们的出勤人数。通过内部联接,出勤和纸张数量似乎相互多重。

需要指导和赞赏。

戴夫

3 个答案:

答案 0 :(得分: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

我看到很多其他答案在滚动,但我输入的时间太长而无法退出;)

答案 1 :(得分: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

答案 2 :(得分: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的引用的问题

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