I think a better approach is to only log entries and exits, for several reasons:
- Some do not go out for lunch.
- Some may end up having to go out more than once in the middle of the day for some reason.
- Some may go out for lunch and not come back in the day for some reason.
I will not consider such cases:
-
Due to some problem, there was no entry record even though there was an exit record or vice versa.
-
There are two entries consecutively without one output in the middle or two outputs consecutively without an input in the middle.
-
Output record without matching entry.
My solution should work even for the case of the worker entering a day and leaving the next day, turning midnight at work. I am living proof that this case happens, I have had problems with HR hours for that very reason. The time in this case is counted the day you entered.
First, let's build a test database:
CREATE TABLE tabela (
id_colaborador int NOT NULL,
horario datetime NOT NULL,
acao varchar(20)
) engine = InnoDB CHARSET = utf8mb4;
INSERT INTO tabela VALUES (1, '2018/09/14 08:00', 'Entrada');
INSERT INTO tabela VALUES (1, '2018/09/14 12:00', 'Almoço');
INSERT INTO tabela VALUES (1, '2018/09/14 13:00', 'Volta almoço');
INSERT INTO tabela VALUES (1, '2018/09/14 17:00', 'Fim de expediente');
INSERT INTO tabela VALUES (1, '2018/09/15 08:00', 'Entrada');
INSERT INTO tabela VALUES (1, '2018/09/15 12:00', 'Almoço');
INSERT INTO tabela VALUES (1, '2018/09/15 13:00', 'Volta almoço');
INSERT INTO tabela VALUES (1, '2018/09/15 17:00', 'Fim de expediente');
INSERT INTO tabela VALUES (2, '2018/09/14 08:30', 'Entrada');
INSERT INTO tabela VALUES (2, '2018/09/14 12:30', 'Almoço');
INSERT INTO tabela VALUES (2, '2018/09/14 13:30', 'Volta almoço');
INSERT INTO tabela VALUES (2, '2018/09/14 17:30', 'Fim de expediente');
INSERT INTO tabela VALUES (2, '2018/09/15 08:30', 'Entrada');
INSERT INTO tabela VALUES (2, '2018/09/15 12:30', 'Almoço');
INSERT INTO tabela VALUES (2, '2018/09/15 13:30', 'Volta almoço');
INSERT INTO tabela VALUES (2, '2018/09/15 17:30', 'Fim de expediente');
-- Virou a meia-noite no trabalho!
INSERT INTO tabela VALUES (3, '2018/09/14 17:00', 'Entrada');
INSERT INTO tabela VALUES (3, '2018/09/15 02:00', 'Almoço');
Now, let's select the input and output pairs:
SELECT
entrada.id_colaborador,
entrada.horario AS entrada,
(
SELECT MIN(s.horario)
FROM tabela s
WHERE s.acao IN ('Almoço', 'Fim de expediente')
AND s.id_colaborador = entrada.id_colaborador
AND s.horario > entrada.horario
) AS saida
FROM tabela entrada
WHERE entrada.acao IN ('Entrada', 'Volta almoço');
The output should be this:
+----------------+----------------------+----------------------+
| id_colaborador | entrada | saida |
+----------------+----------------------+----------------------+
| 1 | 2018-09-14T08:00:00Z | 2018-09-14T12:00:00Z |
| 1 | 2018-09-14T13:00:00Z | 2018-09-14T17:00:00Z |
| 1 | 2018-09-15T08:00:00Z | 2018-09-15T12:00:00Z |
| 1 | 2018-09-15T13:00:00Z | 2018-09-15T17:00:00Z |
| 2 | 2018-09-14T08:30:00Z | 2018-09-14T12:30:00Z |
| 2 | 2018-09-14T13:30:00Z | 2018-09-14T17:30:00Z |
| 2 | 2018-09-15T08:30:00Z | 2018-09-15T12:30:00Z |
| 2 | 2018-09-15T13:30:00Z | 2018-09-15T17:30:00Z |
| 3 | 2018-09-14T17:00:00Z | 2018-09-15T02:00:00Z |
+----------------+----------------------+----------------------+
Once this is done, we only have to join the entry-exit pairs of the day:
SELECT
x.id_colaborador AS id_colaborador,
DAY(x.entrada) AS dia,
SUM(timediff(x.entrada, x.saida)) AS periodo
FROM (
SELECT
entrada.id_colaborador AS id_colaborador,
entrada.horario AS entrada,
(
SELECT MIN(s.horario)
FROM tabela s
WHERE s.acao IN ('Almoço', 'Fim de expediente')
AND s.id_colaborador = entrada.id_colaborador
AND s.horario > entrada.horario
) AS saida
FROM tabela entrada
WHERE entrada.acao IN ('Entrada', 'Volta almoço')
) x
GROUP BY x.id_colaborador, DAY(x.entrada);
The output should be this:
+----------------+------------+---------+
| id_colaborador | dia | periodo |
+----------------+------------+---------+
| 1 | 2018-09-14 | 80000 |
| 1 | 2018-09-15 | 80000 |
| 2 | 2018-09-14 | 80000 |
| 2 | 2018-09-15 | 80000 |
| 3 | 2018-09-14 | 90000 |
+----------------+------------+---------+
This value returned in the period is in the format HMMSS
, that is, the last two digits are the seconds, the previous two the minutes and the rest are the hours.