计算连续日期,不包括SQL中的周末
我正在编写一份缺勤报告,其中需要包括连续缺勤6次的员工,同时统计在给定日期范围内连续缺勤6次或以上的员工人数。我最大的问题是处理周末。因为这是一所学校,员工周一到周五工作,所以为了计算连续的6个日期,总是会有一个周末来分隔日期。我正在处理大量每天都会更新的数据,因此我无法将日期插入此任务的临时表中。我创建了一个临时表,用于存储开始日期和结束日期之间的所有日期,不包括周末:计算连续日期,不包括SQL中的周末,sql,sql-server,Sql,Sql Server,我正在编写一份缺勤报告,其中需要包括连续缺勤6次的员工,同时统计在给定日期范围内连续缺勤6次或以上的员工人数。我最大的问题是处理周末。因为这是一所学校,员工周一到周五工作,所以为了计算连续的6个日期,总是会有一个周末来分隔日期。我正在处理大量每天都会更新的数据,因此我无法将日期插入此任务的临时表中。我创建了一个临时表,用于存储开始日期和结束日期之间的所有日期,不包括周末: CREATE TABLE #TimeCardDates ( ClientID INT
CREATE TABLE #TimeCardDates (
ClientID INT
, EmpUID BIGINT
, BetweenDate DATE
)
;WITH cte AS (
SELECT
@StartDate StartDate
UNION ALL
SELECT
DATEADD(DAY, 1, StartDate)
FROM cte
WHERE StartDate < @EndDate
)
INSERT INTO #TimeCardDates (
ClientID
, EmpUID
, BetweenDate
)
SELECT
e.ClientID
, e.EmpUID
, c.StartDate
FROM cte c
CROSS JOIN (
SELECT e.ClientID, e.EmpUID
FROM Employee e
JOIN #Clients c
ON c.ClientID = e.ClientID
) e
DELETE d
FROM #TimeCardDates d
WHERE DATENAME(WEEKDAY, d.BetweenDate) IN ('Saturday','Sunday')
上述数据的预期结果:
Employee3 Unscheduled Absence 6
有人能帮我弄清楚怎么做吗?要在两个日期(周末除外)之间生成日期,您可以执行以下操作
declare @startdate date,@enddate date
set @startdate=cast('2020-02-01' as date)
set @enddate=cast('2020-03-01' as date)
;with num_dates
as (select row_number() over(order by name)-1 as rnk
from master..spt_values
)
select @startdate
,dateadd(day,rnk,@startdate) as calendar_dates
,rnk
from num_dates
where datepart(dw,dateadd(day,rnk,@startdate)) not in (6,7)
and dateadd(day,rnk,@startdate) <=@enddate
这里有一个选项,使用lag检查前一天是否是连续缺勤。您可能可以将这些步骤合并到较少的CTE中,但我想将其编写出来,以便很容易看到逻辑是如何工作的
注意:我为雇员1添加了一些额外的测试数据,以确保它在6次以上的非连续缺勤中正常工作
create table #test (employee varchar(20), descr varchar(20), dateabsent date)
insert into #test --Create Sample Data
values
('Employee1','UnscheduledAbsence','2020-01-09'),
('Employee1','UnscheduledAbsence','2020-01-23'),
('Employee1','UnscheduledAbsence','2020-01-29'),
('Employee1','UnscheduledAbsence','2020-02-05'),
('Employee1','UnscheduledAbsence','2020-03-02'),
('Employee1','UnscheduledAbsence','2020-03-03'),
('Employee1','UnscheduledAbsence','2020-03-04'),
('Employee1','UnscheduledAbsence','2020-03-07'),
('Employee1','UnscheduledAbsence','2020-03-12'),
('Employee1','UnscheduledAbsence','2020-03-17'),
('Employee2','UnscheduledAbsence','2020-01-06'),
('Employee2','UnscheduledAbsence','2020-01-27'),
('Employee2','UnscheduledAbsence','2020-02-07'),
('Employee2','UnscheduledAbsence','2020-02-13'),
('Employee2','UnscheduledAbsence','2020-02-26'),
('Employee3','UnscheduledAbsence','2020-01-02'),
('Employee3','UnscheduledAbsence','2020-01-03'),
('Employee3','UnscheduledAbsence','2020-01-06'),
('Employee3','UnscheduledAbsence','2020-01-07'),
('Employee3','UnscheduledAbsence','2020-01-08'),
('Employee3','UnscheduledAbsence','2020-01-09')
; with CTE as (select *, datename(dw,dateabsent) as DW --Day of absence
from #test)
, cte2 as (select *
, case when lag(dateabsent) over (partition by employee order by dateabsent) = dateadd(day, -1, dateabsent) --if this absence immediately follows another absence
or dw = 'Monday' and lag(dateabsent) over (partition by employee order by dateabsent) = dateadd(day, -3, dateabsent) --or this is the Monday after a Friday absence
then 1 else 0 end as Consecutive
from CTE)
, cte3 as (select *
, sum(cte2.Consecutive) over (partition by employee order by dateabsent) + 1 as TotalConsecutiveAbsences --sum consecutive absences, add one for the current row absence
from cte2)
select cte3.employee, cte3.descr, cte3.TotalConsecutiveAbsences
from cte3
where cte3.TotalConsecutiveAbsences >= 6
编辑以稍微清理逻辑并添加注释 根据结果,您是否可以显示预期结果6个工作日转换为8个日历日,前提是在此期间没有其他节假日。你可以直接用8个日历日作为差额,这将使你的计算简单得多。如果我理解正确的话,你在问题中说你已经过滤掉了周末,把每个人放在一个只有工作日的临时表中,对吗?如果是这样的话,你可以使用存在的地方,使用间隔6天来检查。我知道这不能回答你的问题,但是这可以帮助确定哪两天是连续的,在两个日期之间,你应该考虑一个警告,我假设只有很多行作为开始日期和结束日期之间的最大差异。
create table #test (employee varchar(20), descr varchar(20), dateabsent date)
insert into #test --Create Sample Data
values
('Employee1','UnscheduledAbsence','2020-01-09'),
('Employee1','UnscheduledAbsence','2020-01-23'),
('Employee1','UnscheduledAbsence','2020-01-29'),
('Employee1','UnscheduledAbsence','2020-02-05'),
('Employee1','UnscheduledAbsence','2020-03-02'),
('Employee1','UnscheduledAbsence','2020-03-03'),
('Employee1','UnscheduledAbsence','2020-03-04'),
('Employee1','UnscheduledAbsence','2020-03-07'),
('Employee1','UnscheduledAbsence','2020-03-12'),
('Employee1','UnscheduledAbsence','2020-03-17'),
('Employee2','UnscheduledAbsence','2020-01-06'),
('Employee2','UnscheduledAbsence','2020-01-27'),
('Employee2','UnscheduledAbsence','2020-02-07'),
('Employee2','UnscheduledAbsence','2020-02-13'),
('Employee2','UnscheduledAbsence','2020-02-26'),
('Employee3','UnscheduledAbsence','2020-01-02'),
('Employee3','UnscheduledAbsence','2020-01-03'),
('Employee3','UnscheduledAbsence','2020-01-06'),
('Employee3','UnscheduledAbsence','2020-01-07'),
('Employee3','UnscheduledAbsence','2020-01-08'),
('Employee3','UnscheduledAbsence','2020-01-09')
; with CTE as (select *, datename(dw,dateabsent) as DW --Day of absence
from #test)
, cte2 as (select *
, case when lag(dateabsent) over (partition by employee order by dateabsent) = dateadd(day, -1, dateabsent) --if this absence immediately follows another absence
or dw = 'Monday' and lag(dateabsent) over (partition by employee order by dateabsent) = dateadd(day, -3, dateabsent) --or this is the Monday after a Friday absence
then 1 else 0 end as Consecutive
from CTE)
, cte3 as (select *
, sum(cte2.Consecutive) over (partition by employee order by dateabsent) + 1 as TotalConsecutiveAbsences --sum consecutive absences, add one for the current row absence
from cte2)
select cte3.employee, cte3.descr, cte3.TotalConsecutiveAbsences
from cte3
where cte3.TotalConsecutiveAbsences >= 6