2014-10-07 5 views
0

У меня есть таблица timeandattandance со следующими полямирасчета рабочего времени для каждого дня недели между диапазоном дат

TAId int(11) NOT NULL AUTO_INCREMENT, PostId int(11) NOT NULL, PositionId int(11) NOT NULL, CreatedBy int(11) NOT NULL, ModifiedBy int(11) NOT NULL, CreatedDate datetime NOT NULL, ModifiedDate datetime NOT NULL, TimeIn datetime NOT NULL, TimeOut datetime DEFAULT NULL, TimeBilled tinyint(1) NOT NULL DEFAULT '0', DeviceId varchar(50) DEFAULT NULL, UserId int(11) DEFAULT NULL, oldid varchar(45) DEFAULT NULL, FromCallIn tinyint(1) DEFAULT '0'

Мне нужно, чтобы получить рабочее время для каждого пользователя на каждый день, сгруппированного по неделям даты окончания между диапазоном дат , то есть мне дали диапазон дат. Во-первых, мне нужно выяснить, что время будет между этим диапазоном дат, тогда мне нужно получить все выходные даты окончания, а затем каждую неделю мне нужно рассчитать рабочее время за каждый день.

Также при вычислении рабочего времени мне нужно проверить, будет ли разница между timein и таймаутом более одного дня, тогда эти рабочие часы будут разделены на два дня вместо одного.

Я знаю, что он немного сложный, и если требуется больше объяснений, пожалуйста, дайте мне знать.

+0

Все ли столбцы, относящиеся к проблеме? – Strawberry

ответ

1

Вот пример/демонстрация одного из возможных подходов:

SELECT r.dt + INTERVAL 7-DAYOFWEEK(r.dt) DAY AS week_ending 
    , t.userid 
    , r.dt 
    , SUM(TIMESTAMPDIFF(SECOND 
      ,GREATEST(r.dt,t.timein) 
      ,LEAST(r.dt+INTERVAL 1 DAY,t.timeout) 
      ) 
     )/3600 AS hours_worked 
    FROM (SELECT '2014-09-28' AS rb, '2014-10-11' AS re) dr 
    JOIN (SELECT DATE(i.timein) AS dt FROM mytable i 
      UNION 
     SELECT DATE(o.timeout) FROM mytable o 
     ) r 
    ON r.dt BETWEEN DATE(dr.rb) AND DATE(dr.re) 
    JOIN mytable t 
    ON t.timein < r.dt+INTERVAL 1 DAY 
    AND t.timeout > r.dt 
GROUP BY t.userid, r.dt 
ORDER BY week_ending, t.userid, r.dt 

ПРИМЕЧАНИЕ: week_ending возвращает дату в субботу следующую (или) дату работы.

Диапазон дат указан во встроенном виде dr (диапазон дат), период начала ввода - столбец rb, дата окончания диапазона - столбец re. Этот пример показывает двухнедельный диапазон, начиная с воскресенья 2014-09-28 в течение двух полных недель, включая время работы в субботу 2014-10-11. (Значение для re может быть получено как целое число дней от rb, чтобы получить 14 полных дней, `rb + INTERVAL 13 DAY)

Сообщается только о часах работы с этими датами или в дни между этими датами , У данного пользователя, у которого не было никакого «времени» работы на заданную дату, не будет возвращена строка для этой даты. (Запрос можно легко настроить, чтобы возвращать строки для всех сотрудников для всех дат в диапазоне и возвращающих нулей.)

Отсутствие таблицы «cal», содержащей все значения даты, мы можем получить отчетливый список дат значения в диапазоне от самой таблицы; это может быть относительно дорогостоящей операцией для большого количества или строк в таблице. Это не приведет к возврату значений даты, которые не отображаются в столбцах timein или timeout. (Если есть период работы более 24 часов, например, начиная с понедельника и заканчивая в среду. В среду нет других строк, которые имеют тайм-аут или тайм-аут, 24 часа работы в этот день будут опущены ... это, скорее всего, крайний угол случай. Имея четкий список всех возможных значений даты имеющихся в календарной таблице позволяет избежать этой проблемы.)


Followup

вашего комментария звучит, как вам нужно перекрестное произведение между отдельный список дней и отдельный список пользователей, а затем внешнее соединение с таблицей рабочих часов.

JOIN (distinct_list_of_dates_r) r 
    ON (r_in_specified_week) 

    CROSS 
    JOIN (distinct_list_of_userid_u) u 
    LEFT 

    JOIN mytable t 
    ON (t_userid_matches_u) 
    AND (t_times_matches_r ) 

А потом GROUP BY идентификатор пользователя из u, а не от t. Вы, скорее всего, захотите заменить значение NULL, возвращаемое с hours_worked, на 0. Функция MySQL IFNULL удобна для этого, IFNULL(expr,0) является сокращением для CASE WHEN expr IS NULL THEN 0 ELSE expr END.Если вы хотите, чтобы общее количество часов в течение всей недели, а не по отдельным дням, сделайте GROUP BY в выражении week_ending, а не на отдельной дате.

+0

spencer7593 Большое спасибо за ваше время. Это не решает всей моей проблемы. Мне нужно получить рабочее время в течение всех дней в течение недели, а также мне нужно также избежать пропущенной проблемы. Было бы очень приятно, если бы вы предоставили мне полное решение с изменениями. – Imran