计算一个月中的个人工作日,不包括假期和病假

时间:2019-06-05 21:51:11

标签: sql sql-server

我需要为每个用户获取他们一周中的多少天(一个月),我有一个表来存储他们不工作的日期范围(病假),还有一个统计表来存储工作日。

ausentismoT将非工作日存储为日期范围,该表如下所示

user ini        fin        --ini = start date | fin = end date
---------------------------
john 06/05/2019 06/05/2019
john 13/05/2019 13/05/2019
john 20/05/2019 24/05/2019

理货表格,存储每月的每一天并将其状态标记为假期:

IDCal   fechaValor  numDiaSemana    nomDia  nomMes  semanaAno   diaJuliano  feriadoBancario feriadoNombre
---------------------------------------------------------------------------------------------
20190502    2019-05-02 00:00:00.000 4   Jueves  Mayo    18  122 0   NULL
20190503    2019-05-03 00:00:00.000 5   Viernes Mayo    18  123 0   NULL
20190504    2019-05-04 00:00:00.000 6   Sábado  Mayo    18  124 1   Weekend

我的代码,在我知道逻辑错误的情况下,我“尝试”排除假日和非工作日,但所有列的结果均为0:

SELECT T.RUT_DV,
T.USER,
DIAS_HAB_MES = (SELECT COUNT(CONVERT(INT,feriadoBancario,112)) AS D FROM CALENDAR C WHERE feriadoBancario=0 AND CONVERT(NVARCHAR(6),C.fechaValor,112) = CONVERT(NVARCHAR(6),GETDATE(),112)),

LUNES = (SELECT COUNT(CONVERT(INT,feriadoBancario,112)) AS D FROM CALENDAR C 
    WHERE numDiaSemana=1 AND feriadoBancario = 0 AND (FECHAVALOR BETWEEN DATEADD(MM, DATEDIFF(MM, 0, GETDATE())-1, 0) AND T2.INI) AND FECHAVALOR BETWEEN DATEADD(MM, DATEDIFF(MM, 0, getdate()), 0)-1 AND T2.FIN),

MARTES = (SELECT COUNT(CONVERT(INT,feriadoBancario,112)) AS D FROM CALENDAR C 
    WHERE numDiaSemana=2 AND feriadoBancario = 0 AND (FECHAVALOR BETWEEN DATEADD(MM, DATEDIFF(MM, 0, GETDATE())-1, 0) AND T2.INI) AND FECHAVALOR BETWEEN DATEADD(MM, DATEDIFF(MM, 0, getdate()), 0)-1 AND T2.FIN),

MIERCOLES = (SELECT COUNT(CONVERT(INT,feriadoBancario,112)) AS D FROM CALENDAR C 
    WHERE numDiaSemana=3 AND feriadoBancario = 0 AND (FECHAVALOR BETWEEN DATEADD(MM, DATEDIFF(MM, 0, GETDATE())-1, 0) AND T2.INI) AND FECHAVALOR BETWEEN DATEADD(MM, DATEDIFF(MM, 0, getdate()), 0)-1 AND T2.FIN),

JUEVES = (SELECT COUNT(CONVERT(INT,feriadoBancario,112)) AS D FROM CALENDAR C 
    WHERE numDiaSemana=4 AND feriadoBancario = 0 AND (FECHAVALOR BETWEEN DATEADD(MM, DATEDIFF(MM, 0, GETDATE())-1, 0) AND T2.INI) AND FECHAVALOR BETWEEN DATEADD(MM, DATEDIFF(MM, 0, getdate()), 0)-1 AND T2.FIN),

VIERNES = (SELECT COUNT(CONVERT(INT,feriadoBancario,112)) AS D FROM CALENDAR C 
    WHERE numDiaSemana=5 AND feriadoBancario = 0 AND (FECHAVALOR BETWEEN DATEADD(MM, DATEDIFF(MM, 0, GETDATE())-1, 0) AND T2.INI) AND FECHAVALOR BETWEEN DATEADD(MM, DATEDIFF(MM, 0, getdate()), 0)-1 AND T2.FIN)

FROM dotacionAD T -- BASE TABLE
LEFT JOIN ausentismoT T2 ON T.RUT_DV = REPLACE(T2.RUT_DV,'.','')

结果是这样的

NOM_COL DIAS_HAB_MES    LUNES   MARTES  MIERCOLES   JUEVES  VIERNES
-------------------------------------------------------------------
JOHN    20  0   0   0   0   0

对于相同的情况,应显示以下内容:

NOM_COL DIAS_HAB_MES    LUNES   MARTES  MIERCOLES   JUEVES  VIERNES
-------------------------------------------------------------------
JOHN    20  1   3   3   4   4

2 个答案:

答案 0 :(得分:0)

我相信您第二次复制粘贴dateadd / datediff时发生了错误。

在我编写此答案时,我的本地getdate()将在2019年6月6日返回。

您的第一个条件是:

FECHAVALOR BETWEEN DATEADD(MM, DATEDIFF(MM, 0, GETDATE())-1, 0) AND T2.INI

此公式将当前日期截断为月级别,并且还减去一个月。因此,如果我现在运行它,我将在2019年5月1日得到回报。您所有的ini都在此之后,所以确定。

您的第二个条件是:

FECHAVALOR BETWEEN DATEADD(MM, DATEDIFF(MM, 0, getdate()), 0)-1 AND T2.FIN

此公式将当前日期截断为月级别,不减去一个月,但最后减去一天。因此,如果我现在运行它,我将在2019年6月2日得到回报。您的鳍片都不会迟于此,这就是为什么您到处都为零的原因。

现在我不确定您打算看到什么,但是两个BETWEEN似乎很奇怪。如果您想使用ausentismoT中的最近两个月,则可以这样写:

FECHAVALOR >= DATEADD(MM, DATEDIFF(MM, 0, GETDATE())-1, 0)
AND
FECHAVALOR BETWEEN T2.INI and T2.FIN

答案 1 :(得分:0)

这应该有助于您入门。尚不清楚您是否提供了所有信息。

select
    t.user, count(*) as dia_hab_mes,
    count(case when numDiaSemana = 1 then 1 end) as lunes,
    ...
from
    users as u cross join calendar as c
    left outer join ausentismoT as a
        on c.<date> between a.ini and a.fin and a.user = t.user
where c.<date> ... /* filter dates for desired month */
    and feriadoBancario = 0
group by u.user;