SQL Count病假日

时间:2014-12-16 10:39:56

标签: sql sql-server sum case case-when

我有一个SQL Server表,其中包含所有员工及其病情的列表。

我需要能够计算他们在本季度患病的天数

问题是,有些人可能已经病了一年,所以,E.G的FROMDATE可能是2013-12-31而UNTILDATE可能是2014-12-31(1年病假)。但是,它应该只计算当前季度发生的疾病的天数。所以它应该是大约90天的疾病,而不是整整一年。

当前SQL

select SUM(a.WORKDAYS) as Total
from ABSENCE a
where a.FROMDATE < GETDATE() and 

a.UNTILDATE > DATEADD(MONTH, -3, GETDATE())
and
a.ABS_REASON='SICK'

所以目前,这需要从任何一个正确的日期开始,因为我需要考虑那些在季度开始之前已经生病但仍然生病的人进入当前季度但是应该只计算从那个时候开始的天数。季度开始到本季度结束。

非常感谢任何帮助。

4 个答案:

答案 0 :(得分:1)

使用日期表,您可以轻松找到日期在两个感兴趣日期之间的日期计数,以及周围存在的休假期。您还可以过滤日期以排除非工作日和公共假日。

有很多方法可以生成这样的日期表,并且在stackoverflow和dba.stackexchange上都有很多描述。

答案 1 :(得分:0)

SELECT SUM(a.WORKDAYS) as Total
FROM ABSENCE a
WHERE (a.FROMDATE >= DATEADD(MONTH, -3, GETDATE()) OR a.UNTILDATE >= DATEADD(MONTH, -3, GETDATE()))
AND a.ABS_REASON = 'SICK'

特定季度

SELECT SUM(a.WORKDAYS) as Total
FROM ABSENCE a
WHERE (a.FROMDATE >= DATEADD(quarter, -1, GETDATE()) OR a.UNTILDATE >= DATEADD(quarter, -1, GETDATE()))
AND a.ABS_REASON = 'SICK'

答案 2 :(得分:0)

不确定你的栏目。你应该只提供在2013-12-31和2014-12-31之间提供记录的sql,然后提出你的问题。

试试这个,

 select SUM(Case when datepart(MM, a.FROMDATE) IN (10,11,12) Then a.WORKDAYS Else  End) 
as Total
   from ABSENCE a
   where a.FROMDATE >= '2013-12-31' and 
   a.UNTILDATE <= '2014-12-31'
   and
   a.ABS_REASON='SICK'

答案 3 :(得分:0)

使用包含所有可能日期列表的日历表非常方便,但在这种情况下,我们可以不使用它。

我会稍微概括一下你的问题。我们没有看当前季度,而是让我们有两个参数来定义您感兴趣的日期范围:

DECLARE @ParamStartDate date;
DECLARE @ParamEndDate date;

首先,我们需要从Absence获取范围从FromDateUntilDate且与给定时间段相交的所有行。

SELECT
    ...
FROM
    Absence
WHERE
    ABS_REASON='SICK'
    -- all absence periods, which overlap with the given period
    AND FromDate <= @ParamEndDate
    AND UntilDate >= @ParamStartDate

(StartA <= EndB)(EndA >= StartB)时,两个时段A和B重叠。

然后我们需要计算两个时期交叉点的天数。

交叉周期不能大于给定的日期范围(@ParamStartDate@ParamEndDate)。

交叉期不能大于疾病的持续时间(FromDateUntilDate)。

因此,交集的开头是FromDate@ParamStartDate的最新版本,即MAX(FromDate, @ParamStartDate)

交叉点的结尾是最早的UntilDate@ParamEndDate,即MIN(UntilDate, @ParamEndDate)

最后,以天为单位的交叉口的持续时间为

DATEDIFF(day, MAX(FromDate, @ParamStartDate), MIN(UntilDate, @ParamEndDate))

但是,只有它是积极的。如果是负数,则意味着疾病期在特定季度开始之前结束(或者在给定季度结束后疾病开始)。

没有内置的MIN,MAX函数可以根据需要使用两个参数,因此我使用CROSS APPLY来计算它们。另外,我计算了给定季度的天数,只是为了完整性。最终查询如下所示:

SELECT
    1+DATEDIFF(day, @ParamStartDate, @ParamEndDate) AS QuarterDays
    ,CASE WHEN 1+DATEDIFF(day, CTE_MaxStartDate.AbsenceStartDate, CTE_MinEndDate.AbsenceEndDate) > 0
        THEN 1+DATEDIFF(day, CTE_MaxStartDate.AbsenceStartDate, CTE_MinEndDate.AbsenceEndDate)
        ELSE 0 END AS AbsenceDays
FROM
    Absence
    CROSS APPLY
    (
        SELECT CASE WHEN UntilDate < @ParamEndDate THEN UntilDate ELSE @ParamEndDate END AS AbsenceEndDate
    ) AS CTE_MinEndDate
    CROSS APPLY
    (
        SELECT CASE WHEN FromDate > @ParamStartDate THEN FromDate ELSE @ParamStartDate END AS AbsenceStartDate
    ) AS CTE_MaxStartDate
WHERE
    ABS_REASON='SICK'
    -- all absence periods, which overlap with the given period
    AND FromDate <= @ParamEndDate
    AND UntilDate >= @ParamStartDate

如果期间的开始日期和结束日期相同,我会向DATEDIFF添加1以获得一天的持续时间。