查询以返回基于今天日期的连续日期的行

时间:2018-08-31 11:30:19

标签: sql sql-server

我有以下问题要解决。我在SQL Server 2008中有一个表,该表具有以下列:

Person, JobType, ShiftDate, Hours

我需要提取连续7个工作日(或计划工作超过52小时的任何人)(或工作或已计划工作超过52小时的任何人),而今天是我的出发点。

注意:人们每天可以轮班工作1次以上。因此,我有一个查询,该查询选择今天前7天和将来7天:

t1.Starton BETWEEN DATEADD(DAY, -7, GETDATE()) AND DATEADD(DAY, 7, GETDATE())

我的想法是,如果我可以选择任何连续的日期范围,而今天在“中间”,那至少会给我一个起点(因为缺少的任何日期都假定为休息日,不计算在内)?我在SO上看到过很多帖子,它们显示了如何从表格中获取连续的日期范围,但我不知道如何以今天为起点。我们将不胜感激地收到任何更好的方法的帮助或建议。

2 个答案:

答案 0 :(得分:2)

因此,您想查找上周和下周内至少有7天连续的天数。

您可以为每个人的连续天数分组。
然后计算每人和日期组的天数。

一旦有了,只需选择一个日期组中有7天或更多天的人。

例如,此测试代码段:

--
-- Using a table variable for easy testing
--
declare @ShiftTable table (Person varchar(30), JobType varchar(8), ShiftDate datetime, [Hours] decimal(5,2));
--
-- Sample Data
--
insert into @ShiftTable (Person, JobType, ShiftDate, [Hours]) values
('Mike','Ast',GetDate()-5,7.5),('Mike','Ast',GetDate()-4,7.5),
('Mike','Ast',GetDate()-3,7.5),('Mike','Ast',GetDate()-2,7.5),('Mike','Ast',GetDate()-1,7.5),('Mike','Ast',GetDate(),7.5),('Mike','Ast',GetDate()+1,7.5),('Mike','Ast',GetDate()+2,7.5),
('Dave','Help',GetDate()-2,7),('Dave','Help',GetDate()-1,7),('Dave','Help',GetDate(),5),
('Pam','Cook',GetDate()-6,8),('Pam','Cook',GetDate()-6,8),('Pam','Cook',GetDate()-4.2,3),('Pam','Cook',GetDate()-4,5),
('Pam','Cook',GetDate()-3.2,4),('Pam','Cook',GetDate()-3,3),('Pam','Cook',GetDate()-2,8),('Pam','Cook',GetDate()-1,8),
('Pam','Cook',GetDate(),8),('Pam','Cook',GetDate()+1,8),('Pam','Cook',GetDate()+3,8);

--
-- Query
--
SELECT DISTINCT Person
FROM
(
    SELECT Person, DateGroup, COUNT(*) AS TotalDays
    -- , MIN(ShiftDate) as MinShiftDate, MAX(ShiftDate) as MaxShiftDate
    FROM
    (
      SELECT Person, CAST(ShiftDate AS DATE) AS ShiftDate,
       DATEADD(day, ROW_NUMBER() OVER (PARTITION BY Person ORDER BY Person, CAST(ShiftDate AS DATE) DESC)-1, CAST(ShiftDate AS DATE)) as DateGroup
      FROM @ShiftTable
      WHERE CAST(ShiftDate AS DATE) BETWEEN CAST(DATEADD(DAY,-6,GETDATE()) AS DATE) AND CAST(GETDATE()+6 AS DATE)
      GROUP BY Person, CAST(ShiftDate AS DATE)
    ) q1
    GROUP BY Person, DateGroup
    HAVING COUNT(*) >= 7
) q2
ORDER BY Person;

返回:

Person
------
Mike

答案 1 :(得分:1)

 --build a date table (you should build a permanent one)

select * into #DateTable from (SELECT dateadd(day,row_number() over (order by a1.name), cast('20180101' as date)) adate from sys.objects a1 cross join sys.objects b ) dq where dq.adate < '20220101'

--make some sample data

SELECT dq.* into #shifts from
(
select 1 as empid, cast('20180901 10:00:00' as datetime2) as starton, cast('20180901 12:00:00' as datetime2) as endOn
union
select 1 as empid, cast('20180902 10:00:00' as datetime2) as starton, cast('20180902 12:00:00' as datetime2) as endOn
union
select 1 as empid, cast('20180903 10:00:00' as datetime2) as starton, cast('20180903 12:00:00' as datetime2) as endOn
union
select 1 as empid, cast('20180904 10:00:00' as datetime2) as starton, cast('20180904 12:00:00' as datetime2) as endOn
union
select 1 as empid, cast('20180904 15:00:00' as datetime2) as starton, cast('20180904 19:00:00' as datetime2) as endOn
union
select 1 as empid, cast('20180905 10:00:00' as datetime2) as starton, cast('20180905 12:00:00' as datetime2) as endOn
union
select 1 as empid, cast('20180906 10:00:00' as datetime2) as starton, cast('20180906 12:00:00' as datetime2) as endOn
union
select 1 as empid, cast('20180907 10:00:00' as datetime2) as starton, cast('20180907 12:00:00' as datetime2) as endOn
union
select 1 as empid, cast('20180908 10:00:00' as datetime2) as starton, cast('20180908 12:00:00' as datetime2) as endOn
union
select 1 as empid, cast('20180910 10:00:00' as datetime2) as starton, cast('20180908 12:00:00' as datetime2) as endOn
union
select 1 as empid, cast('20180911 10:00:00' as datetime2) as starton, cast('20180908 12:00:00' as datetime2) as endOn
union
select 1 as empid, cast('20180912 10:00:00' as datetime2) as starton, cast('20180908 12:00:00' as datetime2) as endOn
union
select 1 as empid, cast('20180913 10:00:00' as datetime2) as starton, cast('20180908 12:00:00' as datetime2) as endOn
union
select 1 as empid, cast('20180914 10:00:00' as datetime2) as starton, cast('20180908 12:00:00' as datetime2) as endOn
union
select 1 as empid, cast('20180915 10:00:00' as datetime2) as starton, cast('20180908 12:00:00' as datetime2) as endOn
union
select 1 as empid, cast('20180916 10:00:00' as datetime2) as starton, cast('20180908 12:00:00' as datetime2) as endOn
union
select 1 as empid, cast('20180917 0:00:00' as datetime2) as starton, cast('20180908 12:00:00' as datetime2) as endOn
union
select 1 as empid, cast('20180919 10:00:00' as datetime2) as starton, cast('20180908 12:00:00' as datetime2) as endOn
union
select 1 as empid, cast('20180919 10:00:00' as datetime2) as starton, cast('20180908 12:00:00' as datetime2) as endOn




) dq;


 --here is the query - find days that are followed by 6 days with shifts in the next 6 days (so shifts that are part of a 7 day run)

SELECT IQ.empid, IQ.starton dayFollowedBy6Shifts from 
(
select s.empid,CASt(s.starton as date) starton, cast(s2.starton as date) starton2 from #shifts s join #DateTable d on  DATEDIFF(DAY, s.starton, d.adate) < 7 and d.adate >= CAST(s.starton as date) join #shifts s2 on  s2.empid = s.empid and cast(s2.starton as date) = d.adate
  Group by s.empid, CASt(s.starton as date), cast(s2.starton as date)

) IQ 
group by IQ.empid,IQ.starton having COUNT(0) >= 7




drop table #datetable;
drop table #shifts;