我正在制作一份不在办公室的报告,正如所建议的那样,当有人关闭时。我被要求包括返回工作日期。所以我需要编写一个查询来检查此人关闭的连续日期。我设法找到一个接近的查询,但由于周末它会绊倒。 所以默认数据是:
StaffCode HolidayDate
J.Smith 2017-04-03 00:00:00.000
J.Smith 2017-04-04 00:00:00.000
J.Smith 2017-04-05 00:00:00.000
J.Smith 2017-04-06 00:00:00.000
J.Smith 2017-04-07 00:00:00.000
J.Smith 2017-04-10 00:00:00.000
J.Smith 2017-04-11 00:00:00.000
J.Smith 2017-04-12 00:00:00.000
J.Smith 2017-04-13 00:00:00.000
J.Smith 2017-04-18 00:00:00.000
当我运行查询时,它返回
FirstDay LastDay
2017-04-03 2017-04-07
2017-04-10 2017-04-13
2017-04-18 2017-04-18
但我想要的是
firstDay lastDay
2017-04-03 2017-04-13
这是我正在使用的查询,有没有办法排除周末?
WITH t AS (
SELECT HolidayDate d,ROW_NUMBER() OVER(ORDER BY HolidayDate) i
FROM tblHoliday
WHERE StaffCode = 'j.Smith'
AND HolidayDate >= '27-Feb-2017'
GROUP BY HolidayDate
)
SELECT MIN(d),MAX(d)
FROM t
GROUP BY DATEDIFF(day,i,d)
答案 0 :(得分:1)
这是Dates
表格派上用场的地方。有许多博客文章建议在数据库中添加Dates
表,以便您需要处理日期。
为了创建Dates
表,您可以使用递归CTE:
;with dates as (
select cast('19000101' as datetime) [current_date]
union all
select dateadd(day, 1, current_date)
from dates
where current_date <= cast('20991231' as datetime)
)
select
[current_date]
, NULL [holiday]
, case datename(weekday, prev_date)
when 'Saturday'
then 1
when 'Sunday'
then 1
else 0
end [weekend]
into Dates
from dates
option(maxrecursion 0);
正如您所看到的,我添加了两个额外的列,这些列可能在将来有用。可以包含一个布尔值来指出特定日期是假日/国庆日 - [holiday]
列。
第3列还包含一个布尔值,指示日期是否为周末。
因此,使用Dates
表,在单个查询中,您可以执行类似(它并不漂亮)的内容:
-- I'll also create the sample data and store it into a timeOff table
create table timeOff (staffCode varchar(25), holidayDate datetime);
insert [dbo].[timeOff] ([staffCode], [holidayDate]) values (N'J.Smith', CAST(N'2017-04-03T00:00:00.000' AS DateTime));
insert [dbo].[timeOff] ([staffCode], [holidayDate]) values (N'J.Smith', CAST(N'2017-04-04T00:00:00.000' AS DateTime));
insert [dbo].[timeOff] ([staffCode], [holidayDate]) values (N'J.Smith', CAST(N'2017-04-05T00:00:00.000' AS DateTime));
insert [dbo].[timeOff] ([staffCode], [holidayDate]) values (N'J.Smith', CAST(N'2017-04-06T00:00:00.000' AS DateTime));
insert [dbo].[timeOff] ([staffCode], [holidayDate]) values (N'J.Smith', CAST(N'2017-04-07T00:00:00.000' AS DateTime));
insert [dbo].[timeOff] ([staffCode], [holidayDate]) values (N'J.Smith', CAST(N'2017-04-10T00:00:00.000' AS DateTime));
insert [dbo].[timeOff] ([staffCode], [holidayDate]) values (N'J.Smith', CAST(N'2017-04-11T00:00:00.000' AS DateTime));
insert [dbo].[timeOff] ([staffCode], [holidayDate]) values (N'J.Smith', CAST(N'2017-04-12T00:00:00.000' AS DateTime));
insert [dbo].[timeOff] ([staffCode], [holidayDate]) values (N'J.Smith', CAST(N'2017-04-13T00:00:00.000' AS DateTime));
insert [dbo].[timeOff] ([staffCode], [holidayDate]) values (N'J.Smith', CAST(N'2017-04-18T00:00:00.000' AS DateTime));
-- And now for the query itself (it's not pretty but I came up with it in a short time)
select
[staffCode]
, min([current_date]) [firstDay]
, max([current_date]) [lastDay]
from
(select d.[current_date]
, t.staffCode
, min(case when d.weekend = 0 and t.holidayDate is null then d.[current_date] else null end) over () [last_date]
from
(select [staffCode]
, min(holidayDate) [mindate]
, max(holidayDate) [maxdate]
from timeOff t
where staffcode = 'J.Smith'
group by staffCode) r
inner join dates d on d.[current_date] between mindate and maxdate
left join timeOff t on d.[current_date] = t.holidayDate ) r
where [current_date] < [last_date]
and staffCode is not null
group by staffCode;