2011-06-24 140 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