我有以下问题要解决。我在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上看到过很多帖子,它们显示了如何从表格中获取连续的日期范围,但我不知道如何以今天为起点。我们将不胜感激地收到任何更好的方法的帮助或建议。
答案 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;