在SQL中计算连续缺勤

在SQL中计算连续缺勤,sql,sql-server,tsql,Sql,Sql Server,Tsql,我需要计算SQL中某个日期范围内连续缺勤X次的所有员工 我们有一个缺勤表,记录员工缺勤的每一天,还有一个日历表,记录一年的工作日 tblAbsences EmployeeID int AbsenceDate datetime tblCalendar WorkDay datetime 有人知道如何计算连续缺勤吗?示例:在2009年1月1日至2009年3月1日期间连续3次缺勤的所有员工。这应该适合您。按日期分组,找出缺席次数超过X次的人 select a.*, (

我需要计算SQL中某个日期范围内连续缺勤X次的所有员工

我们有一个缺勤表,记录员工缺勤的每一天,还有一个日历表,记录一年的工作日

tblAbsences
EmployeeID int
AbsenceDate datetime

tblCalendar
WorkDay datetime

有人知道如何计算连续缺勤吗?示例:在2009年1月1日至2009年3月1日期间连续3次缺勤的所有员工。

这应该适合您。按日期分组,找出缺席次数超过X次的人

select a.*, 
        (
            select min(b.absenceDate) from tblAbsences b where a.employeeId = b.employeeId 
            and b.absenceDate >= a.absenceDate
            and not exists ( 
                select 1 from tblabsences c where c.employeeId = b.employeeId and dateadd( dd, 1, b.absenceDate) = c.absenceDate  
            )
) ConsecDates
from dbo.tblAbsences a
order by a.AbsenceDate asc

在PostgreSQL中测试;SQL使用POST中的示例值

提供的表中没有定义主键,下面的代码解决了这一问题。最好是添加主键并优化以下代码以利用它们:更好的数据质量、更好的性能、更干净的代码、更快乐的人

删除tbl前缀在数据库实现中提供了更大的灵活性。表、视图和同义词可以互换使用,而不会影响引用数据库对象的代码或破坏命名约定

/* period length as the desired number of consecutive days */
/* time window as the period to be analyzed */
SELECT DISTINCT
 /* Consolidate employees with multiple periods */
 a.employeeid
FROM
 (SELECT
   /* Generate all possible periods */
   pk_c.workday begin_date,
   /* End date for given period length; less one for closed boundaries */
   LEAD(pk_c.workday,3-1,NULL) OVER (ORDER BY pk_c.workday) end_date 
  FROM (SELECT DISTINCT
         /* No calendar PK, remove dupes; if PK, pull in-line view up */
         c.workday
        FROM sandbox.calendar c) pk_c
       ) p
 INNER JOIN sandbox.absences a ON 
  /* Match absences with periods */
  (a.absencedate BETWEEN p.begin_date AND p.end_date)
WHERE
 /* In time window desired; exclude periods extending beyond boundaries */
 (p.begin_date BETWEEN '2009-01-01' AND '2009-03-01'
  AND /* NOT NULL exclusion implied for periods beyond calendar boundaries */
  p.end_date BETWEEN '2009-01-01' AND '2009-03-01')
GROUP BY
 a.employeeid,
 /* Also group period, display only employee */
 p.begin_date
HAVING
 /* Number of absence days to match to the period length */
 /* DISTINCT due to missing absences PK; if PK, drop DISTINCT */
 COUNT(DISTINCT a.absencedate) = 3
;
享受。以下版本:

SELECT DISTINCT
 a.employeeid
FROM
 (SELECT
   pk_c.workday begin_date,
   LEAD(pk_c.workday,3-1,NULL) OVER (ORDER BY pk_c.workday) end_date 
  FROM (SELECT DISTINCT c.workday FROM sandbox.calendar c) pk_c) p
 INNER JOIN sandbox.absences a ON 
  (a.absencedate BETWEEN p.begin_date AND p.end_date)
WHERE
 (p.begin_date BETWEEN '2009-01-01' AND '2009-03-01'
  AND p.end_date BETWEEN '2009-01-01' AND '2009-03-01')
GROUP BY
 a.employeeid, p.begin_date
HAVING
 COUNT(DISTINCT a.absencedate) = 3
;

杰夫关于Woot徽章的问题可能与此相关:这非常有效,除了我还需要排除周末。示例:星期四、星期五和星期一休息是连续3天。(星期六和星期天不在tblAbsences中)如果b.缺勤日期是星期五,则我增加了3天,而且似乎有效。谢谢还有(DATEADD(dd,1,b.absenceDate)=c.absenceDate或((DATENAME(dw,b.absenceDate)='Friday')和DATEADD(dd,3,b.absenceDate)=c.absenceDate)假期呢?这个解决方案根本不使用日历表。Holdiays是一个不错的选择。如果有人能把它加进去,那就太好了。