2017-01-13 13 views
1

У меня есть требование, когда мне нужно создать отчет, используя данные ниже ежемесячно для каждого сотрудника. Отчет работает 1-го числа каждого месяца и предоставляет данные до 1-го числа прошлого месяца. Требование состоит в том, чтобы разделить эти данные на недельные данные. Поэтому, если 1-й день каждого месяца начинается с «Понедельника», а неделя должна быть 5 рабочих дней, «вторник» - 4 рабочих дня, «среда» - 3 рабочих дня и т. Д .. И вычислить рабочее время в зависимости от того дня, в который работал сотрудник соответствующая неделя. Если количество недель меняется каждый месяц, чем отчет должен показывать данные соответственно на каждую неделю.Разделить ежемесячные рабочие часы на еженедельные часы - SQL Server

EmpName Date  WorkTime 
User1 2016-10-18 NULL 
User1 2016-10-20 06:00:38 
User1 2016-10-21 07:41:44 
User1 2016-10-24 06:35:53 
User1 2016-10-25 06:29:03 
User1 2016-10-26 07:25:09 
User1 2016-10-31 07:49:12 
User1 2016-11-03 09:23:05 
User1 2016-11-05 NULL 
User1 2016-11-07 09:18:38 
User1 2016-11-08 09:16:01 
User1 2016-11-09 08:05:03 
User1 2016-11-11 09:00:43 
User1 2016-11-16 09:18:14 

Ниже приведены ожидаемые результаты по вышеуказанному запросу.

WeekNum WeekDur   EmpName Planned  Actual 
Week1 18/10 - 22/10 User1 32:00:00 13:42:22 
Week2 23/10 - 29/10 User1 40:00:00 20:30:05 
Week3 30/10 - 31/10 User1 8:00:00  7:49:12 

Примечание: Планируемые часов рассчитываются на основе числа дней недели. Средство Пн-Пт, поэтому 8 часов в день дадут 40 часов на 5-дневную неделю. Тем не менее, фактические часы должны быть рассчитаны на все 7 дней, чтобы, если кто-то работает в выходные дни, чем фактический, может соответственно отразиться на любые дополнительные часы, чем запланированные часы.

Примечание: NULL означает, что сотрудник не выполнил ввод/вывод Swipe правильно.

Извините, но я ничего не пробовал сам, так как я новичок в соблюдении этих требований и имею очень мало опыта в обработке даты & запросов времени.

Надеюсь, что предоставил всю информацию и попросил всех связаться со мной в случае возникновения каких-либо вопросов или путаницы.

ответ

0

Я не думаю, что у вас действительно может быть тип данных 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 ║ 
╚═════════╩═════════════════════════╩═════════════════════════╩═════════════════════════╩════════════════════╩═════════════╩═══════════════╩═══════════════╝ 
+0

Благодарим за отзыв, однако приведенное выше верно в соответствии с сценарием. Если вы видите первую строку, между 17 октября и 23 октября мы имеем 5 рабочих дней (с понедельника по пятницу), а HoursPlanned должно быть 40 (счет (1) * 8), но результаты показываются 24 часа, что составляет 3 дня только. Я ищу решение, которое поможет мне рассчитать недельные часы с 1-го числа каждого месяца независимо от того дня, который был на этот день. Надеюсь, это поможет лучше понять это требование. –

+0

@ankurjain Правильно, да, ответьте на обновления. – iamdave

 Смежные вопросы

  • Нет связанных вопросов^_^