Я не думаю, что у вас действительно может быть тип данных time
, который превышает 24 часа, поэтому я разбил ваше время на отдельные поля, чтобы вы могли делать то, что хотите. Вы могли бы покончить с cte
, просто добавив большую дату case
заявления в ваш group by
, но это будет означать дублированный код и поэтому дублируются усилия, чтобы обновить его, и я ленивая:
declare @t table (EmpName nvarchar(10), WorkDate date, WorkTime time);
insert into @t values
('User1','20161018',NULL),('User1','20161020','06:00:38'),('User1','20161021','07:41:44'),('User1','20161024','06:35:53'),('User1','20161025','06:29:03'),('User1','20161026','07:25:09'),('User1','20161031','07:49:12'),('User1','20161103','09:23:05'),('User1','20161105',NULL),('User1','20161107','09:18:38'),('User1','20161108','09:16:01'),('User1','20161109','08:05:03'),('User1','20161111','09:00:43'),('User1','20161116','09:18:14');
with cte as
(
select EmpName
-- Pick the later of either the start of the current week or the current month.
,case when dateadd(wk, datediff(wk,0,WorkDate), 0) < dateadd(month,datediff(month,0,WorkDate),0)
then dateadd(month,datediff(month,0,WorkDate),0) -- This calculates the start of the month.
else dateadd(wk, datediff(wk,0,WorkDate), 0) -- This calculated the start of the week.
end as WeekStart
-- Pick the earlier of either the end of the current week or the current month.
,case when dateadd(d,6,dateadd(wk, datediff(wk,0,WorkDate), 0)) >= dateadd(month,datediff(month,0,WorkDate)+1,0)
then dateadd(d,-1,dateadd(month,datediff(month,0,WorkDate)+1,0)) -- This calculates the last day of the month.
else dateadd(d,6,dateadd(wk, datediff(wk,0,WorkDate), 0)) -- This calculates the last day of the week.
end as WeekEnd
-- Pick the earlier of either the friday of the current week or or the end of the current month.
,case when dateadd(d,4,dateadd(wk, datediff(wk,0,WorkDate), 0)) > case when dateadd(d,6,dateadd(wk, datediff(wk,0,WorkDate), 0)) >= dateadd(month,datediff(month,0,WorkDate)+1,0)
then dateadd(d,-1,dateadd(month,datediff(month,0,WorkDate)+1,0)) -- This calculates the last day of the month.
else dateadd(d,6,dateadd(wk, datediff(wk,0,WorkDate), 0)) -- This calculates the last day of the week.
end
then case when dateadd(d,6,dateadd(wk, datediff(wk,0,WorkDate), 0)) >= dateadd(month,datediff(month,0,WorkDate)+1,0)
then dateadd(d,-1,dateadd(month,datediff(month,0,WorkDate)+1,0)) -- This calculates the last day of the month.
else dateadd(d,6,dateadd(wk, datediff(wk,0,WorkDate), 0)) -- This calculates the last day of the week.
end
else dateadd(d,4,dateadd(wk, datediff(wk,0,WorkDate), 0)) -- This calculates the Friday of the week.
end as WorkingWeekEnd
,datepart(hour,WorkTime) as HoursWorked
,datepart(minute,WorkTime) as MinutesWorked
,datepart(second,WorkTime) as SecondsWorked
from @t
)
select EmpName
,WeekStart
,WeekEnd
,WorkingWeekEnd
,avg(datediff(d,WeekStart,WorkingWeekEnd)+1) * 8 as PlannedHoursWorked
,isnull(sum(HoursWorked),0) as HoursWorked
,isnull(sum(MinutesWorked),0) as MinutesWorked
,isnull(sum(SecondsWorked),0) as SecondsWorked
from cte
group by EmpName
,WeekStart
,WeekEnd
,WorkingWeekEnd
order by EmpName
,WeekStart;
Выход:
╔═════════╦═════════════════════════╦═════════════════════════╦═════════════════════════╦════════════════════╦═════════════╦═══════════════╦═══════════════╗
║ EmpName ║ WeekStart ║ WeekEnd ║ WorkingWeekEnd ║ PlannedHoursWorked ║ HoursWorked ║ MinutesWorked ║ SecondsWorked ║
╠═════════╬═════════════════════════╬═════════════════════════╬═════════════════════════╬════════════════════╬═════════════╬═══════════════╬═══════════════╣
║ User1 ║ 2016-10-17 00:00:00.000 ║ 2016-10-23 00:00:00.000 ║ 2016-10-21 00:00:00.000 ║ 40 ║ 13 ║ 41 ║ 82 ║
║ User1 ║ 2016-10-24 00:00:00.000 ║ 2016-10-30 00:00:00.000 ║ 2016-10-28 00:00:00.000 ║ 40 ║ 19 ║ 89 ║ 65 ║
║ User1 ║ 2016-10-31 00:00:00.000 ║ 2016-10-31 00:00:00.000 ║ 2016-10-31 00:00:00.000 ║ 8 ║ 7 ║ 49 ║ 12 ║
║ User1 ║ 2016-11-01 00:00:00.000 ║ 2016-11-06 00:00:00.000 ║ 2016-11-04 00:00:00.000 ║ 32 ║ 9 ║ 23 ║ 5 ║
║ User1 ║ 2016-11-07 00:00:00.000 ║ 2016-11-13 00:00:00.000 ║ 2016-11-11 00:00:00.000 ║ 40 ║ 35 ║ 39 ║ 85 ║
║ User1 ║ 2016-11-14 00:00:00.000 ║ 2016-11-20 00:00:00.000 ║ 2016-11-18 00:00:00.000 ║ 40 ║ 9 ║ 18 ║ 14 ║
╚═════════╩═════════════════════════╩═════════════════════════╩═════════════════════════╩════════════════════╩═════════════╩═══════════════╩═══════════════╝
Благодарим за отзыв, однако приведенное выше верно в соответствии с сценарием. Если вы видите первую строку, между 17 октября и 23 октября мы имеем 5 рабочих дней (с понедельника по пятницу), а HoursPlanned должно быть 40 (счет (1) * 8), но результаты показываются 24 часа, что составляет 3 дня только. Я ищу решение, которое поможет мне рассчитать недельные часы с 1-го числа каждого месяца независимо от того дня, который был на этот день. Надеюсь, это поможет лучше понять это требование. –
@ankurjain Правильно, да, ответьте на обновления. – iamdave