连续几天不包括周末SQL 2008

时间:2017-02-28 08:14:48

标签: sql-server sql-server-2008-r2

我正在制作一份不在办公室的报告,正如所建议的那样,当有人关闭时。我被要求包括返回工作日期。所以我需要编写一个查询来检查此人关闭的连续日期。我设法找到一个接近的查询,但由于周末它会绊倒。 所以默认数据是:

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)

1 个答案:

答案 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;