Прежде всего, для будущих вопросов, пожалуйста, воздержитесь от использования изображения при публикации. Вместо этого используйте текст, чтобы любой, кто намеревается помочь, мог быстрее генерировать ваш сценарий. Пожалуйста, обратитесь к ссылке , опубликованной Strawberry в комментарии для получения дополнительной информации.
Итак, по вашему вопросу давайте начнем с чего-то простого. Поскольку вы используете MariaDB 10.4+, это хорошая новость, поскольку эта версия поддерживает новые функции; и здесь я собираюсь продемонстрировать один из них; ROW_NUMBER()
, см. Официальные документы MariaDB здесь .
Базовый запрос таков:
SELECT ROW_NUMBER() OVER (PARTITION BY DATE ORDER BY DATE, TIME) AS row_num,
id, MachineIp, FingerId, DATE, TIME, STATUS, Verified, DateCreated
FROM HrAttLogs;
Что ROW_NUMBER()
делает здесь, назначает номер строки (ранг) для каждой строки, разбитой по дате, и порядок по дате, времени; что дает вам это:
+---------+------+-------------+----------+------------+----------+--------+----------+---------------------+
| row_num | id | MachineIp | FingerId | DATE | TIME | STATUS | Verified | DateCreated |
+---------+------+-------------+----------+------------+----------+--------+----------+---------------------+
| 1 | 12 | 10.20.20.73 | 2 | 2019-12-26 | 07:54:25 | 0 | 1 | 2019-12-26 11:09:21 |
| 2 | 216 | 10.20.20.73 | 2 | 2019-12-24 | 16:23:10 | 1 | 1 | 2019-12-26 11:09:21 |
| 1 | 272 | 10.20.20.73 | 2 | 2019-12-24 | 07:52:25 | 0 | 1 | 2019-12-26 11:09:21 |
| 1 | 426 | 10.20.20.73 | 2 | 2019-12-23 | 07:43:44 | 0 | 1 | 2019-12-26 11:09:22 |
| 1 | 709 | 10.20.20.73 | 2 | 2019-12-30 | 07:28:42 | 0 | 1 | 2019-12-30 09:54:21 |
| 2 | 913 | 10.20.20.73 | 2 | 2019-12-28 | 14:05:05 | 1 | 1 | 2019-12-30 09:54:22 |
| 1 | 978 | 10.20.20.73 | 2 | 2019-12-28 | 07:22:32 | 0 | 1 | 2019-12-30 09:54:22 |
| 1 | 1468 | 10.20.20.73 | 2 | 2019-12-31 | 17:57:16 | 1 | 1 | 2020-01-02 10:08:45 |
| 2 | 1796 | 10.20.20.73 | 2 | 2020-01-09 | 18:04:37 | 1 | 1 | 2020-01-10 09:50:28 |
| 1 | 1892 | 10.20.20.73 | 2 | 2020-01-09 | 07:51:52 | 0 | 1 | 2020-01-10 09:50:29 |
| 1 | 2079 | 10.20.20.73 | 2 | 2020-01-08 | 06:56:55 | 0 | 1 | 2020-01-10 09:50:29 |
| 2 | 2163 | 10.20.20.73 | 2 | 2020-01-07 | 16:21:30 | 1 | 1 | 2020-01-10 09:50:29 |
| 1 | 2221 | 10.20.20.73 | 2 | 2020-01-07 | 07:51:57 | 0 | 1 | 2020-01-10 09:50:29 |
+---------+------+-------------+----------+------------+----------+--------+----------+---------------------+
Обратите внимание на поле row_num
в начале. Затем сделайте это как подзапрос и выполните GROUP_CONCAT
с CASE
выражением для row_num
, чтобы получить datein, dateout, scanin и scan:
SELECT fingerid,
GROUP_CONCAT(CASE WHEN row_num=1 THEN DATE END) AS datein,
GROUP_CONCAT(CASE WHEN row_num=2 THEN DATE END) AS dateout,
GROUP_CONCAT(CASE WHEN row_num=1 THEN TIME END) AS scanin,
GROUP_CONCAT(CASE WHEN row_num=2 THEN TIME END) AS scanout
FROM (SELECT ROW_NUMBER() OVER (PARTITION BY DATE ORDER BY DATE, TIME) AS row_num,
id, MachineIp, FingerId, DATE, TIME, STATUS, Verified, DateCreated
FROM HrAttLogs) A
GROUP BY DATE;
Приведенный выше запрос вернет следующий результат :
+----------+------------+------------+-----------+----------+
| fingerid | datein | dateout | scanin | scanout |
+----------+------------+------------+-----------+----------+
| 2 | 2019-12-23 | | 07:43:44 | |
| 2 | 2019-12-24 | 2019-12-24 | 07:52:25 | 16:23:10 |
| 2 | 2019-12-26 | | 07:54:25 | |
| 2 | 2019-12-28 | 2019-12-28 | 07:22:32 | 14:05:05 |
| 2 | 2019-12-30 | | 07:28:42 | |
| 2 | 2019-12-31 | | 17:57:16 | |
| 2 | 2020-01-07 | 2020-01-07 | 07:51:57 | 16:21:30 |
| 2 | 2020-01-08 | | 06:56:55 | |
| 2 | 2020-01-09 | 2020-01-09 | 07:51:52 | 18:04:37 |
+----------+------------+------------+-----------+----------+
Здесь вы уже можете начать использовать JOIN
на других таблицах для получения дополнительной информации. Последняя часть запроса состоит в том, чтобы просто присвоить WorkhourIn
и Workhourout
, используя выражение CASE
, как показано ниже:
SELECT *,
CASE WHEN scanin < '07:00:00' THEN '21:00:00'
WHEN scanin < '14:00:00' THEN '07:00:00'
WHEN scanin < '21:00:00' THEN '14:00:00' END AS 'WorkHourIn',
CASE WHEN scanin < '07:00:00' THEN '07:00:00'
WHEN scanin < '14:00:00' THEN '14:00:00'
WHEN scanin < '21:00:00' THEN '21:00:00' END AS 'WorkHourOut'
FROM
(SELECT fingerid,
GROUP_CONCAT(CASE WHEN row_num=1 THEN DATE END) AS datein,
GROUP_CONCAT(CASE WHEN row_num=2 THEN DATE END) AS dateout,
GROUP_CONCAT(CASE WHEN row_num=1 THEN TIME END) AS scanin,
GROUP_CONCAT(CASE WHEN row_num=2 THEN TIME END) AS scanout
FROM (SELECT ROW_NUMBER() OVER (PARTITION BY DATE ORDER BY DATE, TIME) AS row_num,
id, MachineIp, FingerId, DATE, TIME, STATUS, Verified, DateCreated
FROM HrAttLogs) A
GROUP BY DATE) B ;
Это даст вам результат:
+----------+------------+------------+----------+----------+------------+-------------+
| fingerid | datein | dateout | scanin | scanout | WorkHourIn | WorkHourOut |
+----------+------------+------------+----------+----------+------------+-------------+
| 2 | 2019-12-23 | | 07:43:44 | | 07:00:00 | 14:00:00 |
| 2 | 2019-12-24 | 2019-12-24 | 07:52:25 | 16:23:10 | 07:00:00 | 14:00:00 |
| 2 | 2019-12-26 | | 07:54:25 | | 07:00:00 | 14:00:00 |
| 2 | 2019-12-28 | 2019-12-28 | 07:22:32 | 14:05:05 | 07:00:00 | 14:00:00 |
| 2 | 2019-12-30 | | 07:28:42 | | 07:00:00 | 14:00:00 |
| 2 | 2019-12-31 | | 17:57:16 | | 14:00:00 | 21:00:00 |
| 2 | 2020-01-07 | 2020-01-07 | 07:51:57 | 16:21:30 | 07:00:00 | 14:00:00 |
| 2 | 2020-01-08 | | 06:56:55 | | 21:00:00 | 07:00:00 |
| 2 | 2020-01-09 | 2020-01-09 | 07:51:52 | 18:04:37 | 07:00:00 | 14:00:00 |
+----------+------------+------------+----------+----------+------------+-------------+
Сейчас Я знаю, что это совершенно новый запрос для вас, но, как я уже сказал, может быть способ значительно сократить исходный запрос, и я стремился к этому в начале. Надеюсь, это будет полезно.
Кстати, вот скрипка для всего вышеперечисленного: https://www.db-fiddle.com/f/riiCi8tjtMaBk64fG6hd4K/0
Обновление Для последующего вопрос, попробуйте следующее:
SELECT i.FingerId,fs.ShiftId,MIN(i.Date) AS 'Date',
/*added CASE expression to deal with overlapping attendance date*/
CASE WHEN MIN(i.Time) >= '21:00:00'
THEN DATE(DATE_ADD(i.Date, INTERVAL + 1 DAY))
ELSE DATE(DATE_ADD(i.Date, INTERVAL + s.DayOut DAY)) END AS 'DateOut',
MIN(i.Time) AS 'Time',
s.ShiftIn_1,s.ShiftIn_2,s.ShiftIn_3,s.ShiftOut_1,s.ShiftOut_2,s.ShiftOut_3,
s.WorkhourIn_1,s.WorkhourIn_2,s.WorkhourIn_3,s.WorkhourOut_1,
s.WorkhourOut_2,s.WorkhourOut_3
FROM HrAttLogs AS i
INNER JOIN HrEmployee AS fs ON fs.FingerId = i.FingerId
INNER JOIN HrEmployeeShift AS s ON s.Id = fs.ShiftId
WHERE i.Time >= s.ShiftIn_1
AND i.Date >= '2020-01-01'
AND i.Date <= '2020-01-10'
AND i.MachineIp = '10.20.20.73'
GROUP BY i.FingerId, i.date
Тогда ваше CASE
выражение для WorkhourOut
изменится на следующее:
/*added check for date too.. the last checking is for any overlapping date*/
CASE WHEN i.dateout = i.date AND i.Time > i.ShiftOut_1 THEN i.WorkhourOut_2
WHEN i.dateout = i.date AND i.Time > i.ShiftOut_2 THEN i.WorkhourOut_3
WHEN i.dateout = i.date AND i.Time > i.ShiftOut_3 THEN i.WorkhourOut_1
WHEN i.dateout > i.date THEN i.WorkhourOut_3
END AS WorkhourOut,