2017-02-25 22 views
2

我有一張表,用於存儲學生每天的出勤率。我需要找到連續缺課3天的學生。但是,出勤的日期並不是一個訂單,有些日子像無人蔘加,節假日,週末都被排除在外。學生出席的日期是該表中存在記錄的日期。SQL Server:發現學生在自定義日期的連續缺課計數

的數據是一樣

StudentId  Date   Attendance 
----------------------------------------- 
178234   1/1/2017   P 
178234   5/1/2107   A 
178234   6/1/2107   A 
178234   11/1/2107   A 
178432   1/1/2107   P 
178432   5/1/2107   A 
178432   6/1/2107   P 
178432   11/1/2107   A 

在上述情況下的結果應該是

StudentId  AbsenceStartDate  AbsenceEndDate  ConsecutiveAbsences 
---------------------------------------------------------------------------- 
178234   5/1/2017    11/1/2017   3 

我試圖實施該解決方案Calculating Consecutive Absences in SQL然而,僅在只有工作才能爲日期。任何建議將是偉大的,謝謝

+0

[xkcd PSA ISO 8601](https://xkcd.com/1179/) – SqlZim

+0

學生出席的日期是該表中存在記錄的日期 – user1375481

+0

因此要確認,學生應該參加的所有日期都是記錄在表格中,它是「出勤」列,告訴你當天他們是否在場(P)或缺席(A)? – Skippy

回答

5

哦,你有缺席和禮物在表中。您可以使用row_numbers()做法上的不同:

select studentid, min(date), max(date) 
from (select a.*, 
      row_number() over (partition by studentid order by date) as seqnum, 
      row_number() over (partition by studentid, attendance order by date) as seqnum_a 
     from attendance a 
    ) a 
where attendance = 'A' 
group by studentid, (seqnum - seqnum_a) 
having count(*) >= 3; 

行號之差變得是相同連續值。這是一個有點棘手的理解,但如果你運行子查詢,你應該看到連續缺席或禮物的差異是如何的。你只關心缺席,因此外部查詢中的where

+0

優秀的答案,花了一段時間讓我真正明白。 – user1375481

1

試試這個:

declare @t table (sid int, d date, att char(1)) 
insert @t (sid,d, att) values 
(178234, '1/1/2017','P'), 
(178234, '5/1/2017','A'), 
(178234, '6/1/2017','A'), 
(178234, '11/1/2017','A'), 
(178432, '1/1/2017','P'), 
(178432, '5/1/2017','A'), 
(178432, '6/1/2017','P'), 
(178432, '11/1/2017','A') 

Select s.sid, Min(s.d) startDt, Max(e.d) endDt, s.att, e.att, count(*) 
from @t s join @t e on e.d <= 
    (select max(d) from @t m 
    Where sid = s.sid 
     and d > s.d 
     and att = 'A' 
     and not exists 
      (Select * from @t 
      where sid = s.sid 
       and d between s.d and m.d 
       and att = 'P')) 
Where s.att = 'A' 
    and s.d = (Select Min(d) from @t 
       Where sid = s.sid 
       and d < e.d 
       and att = 'A') 
group by s.sid, s.d, s.att, e.att 

這也是棘手的解釋: 基本上,它使用別名s(對於開始)和E(最終),其中S-行加入表本身在一組連續的缺席中的第一行,以及e。所有的行都在緊接着存在螺柱的下一個日期之前的缺席。這將生成一組所有'A',其中沒有P行。然後通過適當的值對sql組返回每個組中最早和最晚的日期以及行數。
最後的where子句確保s行是組中的第一行。