Get count of continuous dates in mysql

自作多情 提交于 2020-01-05 04:21:06

问题


I have a requirement to get count of continuous dates in leaves table.

CREATE TABLE leaves(
id INT AUTO_INCREMENT PRIMARY KEY ,
employee_id INT NOT NULL,
leave_request_id INT NOT NULL,
leave_date DATE NOT NULL,
start_time time NOT NULL DEFAULT '00:00:00',
end_time time NOT NULL DEFAULT '00:00:00'
);


INSERT INTO `leaves` (`id`, `leave_request_id`, `leave_date`, `employee_id`, `start_time`, `end_time`) VALUES (NULL, '1', '2019-10-01', '2', '09:00:00.000000', '18:00:00.000000'), (NULL, '1', '2019-10-02', '2', '09:00:00.000000', '18:00:00.000000'), (NULL, '1', '2019-10-03', '2', '09:00:00.000000', '18:00:00.000000'), (NULL, '2', '2019-10-08', '2', '09:00:00.000000', '18:00:00.000000'), (NULL, '3', '2019-10-14', '3', '09:00:00.000000', '18:00:00.000000'), (NULL, '4', '2019-10-15', '3', '09:00:00.000000', '18:00:00.000000'), (NULL, '5', '2019-10-16', '3', '09:00:00.000000', '18:00:00.000000'), (NULL, '6', '2019-09-30', '5', '09:00:00.000000', '18:00:00.000000'), (NULL, '6', '2019-10-01', '5', '09:00:00.000000', '18:00:00.000000'), (NULL, '7', '2019-10-01', '8', '09:00:00.000000', '18:00:00.000000');

SqlFiddle Link is: sqlfiddle

I have a following table records:

id  employee_id     leave_request_id    leave_date  start_time  end_time
1   2               1                   2019-10-01  09:00:00    18:00:00
2   2               1                   2019-10-02  09:00:00    18:00:00
3   2               1                   2019-10-03  09:00:00    18:00:00
4   2               2                   2019-10-08  09:00:00    18:00:00
5   3               3                   2019-10-14  09:00:00    18:00:00
6   3               4                   2019-10-15  09:00:00    18:00:00
7   3               5                   2019-10-16  09:00:00    18:00:00
8   5               6                   2019-09-30  09:00:00    18:00:00
9   5               6                   2019-10-01  09:00:00    18:00:00
10  8               7                   2019-10-01  09:00:00    18:00:00

I have tried following query which is GROUP BY leave_request_id.

SELECT employee_id,
       min(leave_date) AS min_applied_date, 
       max(leave_date) AS max_applied_date, 
       SUM(1) AS consec_length_days 
FROM leaves 
GROUP By leave_request_id;

In the above query, min_applied_date is minimum date in a single leave_request_id and max_applied_date is maximum date in a single leave_request_id. leave_consec_length is number of consecutive days in a single leave_request_id. But, sometimes, employee takes consecutive leaves in a single leave request like in records with id 5,6,7. Employee 3 has taken consecutive leaves from 2019-10-14 to 2019-10-16 but with different leave request. So, I want additional column actual_consect_length which count consecutive leave dates in each leave_request.

I want output like following means showing column actual_consect_length (actual consecutive length) with following data.

employee_id  min_applied_date  max_applied_date  leave_consec_length  actual_consect_length
2            2019-10-01        2019-10-03        3                    3
2            2019-10-08        2019-10-08        1                    1
3            2019-10-14        2019-10-14        1                    3
3            2019-10-15        2019-10-15        1                    3
3            2019-10-16        2019-10-16        1                    3
5            2019-09-30        2019-10-01        2                    2
8            2019-10-01        2019-10-01        1                    1

Any help would be appreciated.


回答1:


Sql isn't really made for this and wpuld be somewhat easier in 8.0x with its window fuctions.

This sql statement

Select 
  MIN(employee_id) employee_id
  ,min(`leave_date`) min_applied_date  
  ,max(`leave_date`) max_applied_date  
  ,SUM(leavecount) +1 leave_consec_length
  ,Max(t4.activecount) actual_consect_length

FROM
(SELECT 
  employee_id
    ,`leave_date`
    , leave_request_id
  ,if(@leavereq = leave_request_id,IF(employee_id = @employee
          ,1
          ,0),0) leavecount
 ,if(@employee = employee_id,IF(@date = DATE_SUB(leave_date, INTERVAL 1 DAY)
          ,@active := @active +1
          ,@active :=1),@active := 1) activecount
  ,if(@employee = employee_id,IF(@date = DATE_SUB(leave_date, INTERVAL 1 DAY)
          ,@group1 := @group1 
          ,@group1 := @group1 +1),@group1 := @group1 + 1) group1
  ,@employee := employee_id
  ,@leavereq := leave_request_id  
  ,@date := leave_date
  FROM 
    leaves
    , (Select @employee :=0) r
    , (Select @leavereq :=0) s
   , (Select @group1 :=0) u
    , (Select @date := "1970-1-2") t
 ORDER BY employee_id,leave_date) t2 inner join
 ( SELECT
     GROUP_CONCAT(DISTINCT leave_request_id) leave_request_id
   ,group1
   ,max(activecount) activecount
   FROM (
    SELECT
    leave_request_id
    ,if(@employee = employee_id,IF(@date = DATE_SUB(leave_date, INTERVAL 1 DAY)
          ,@active := @active +1
          ,@active :=1),@active := 1) activecount
  ,if(@employee = employee_id,IF(@date = DATE_SUB(leave_date, INTERVAL 1 DAY)
          ,@group := @group 
          ,@group := @group+1),@group := @group+ 1) group1
      ,@employee := employee_id
  ,@date := leave_date
  FROM 
    leaves
    , (Select @employee :=0) r
   , (Select @group :=0) u
    , (Select @date := "1970-1-2") t
     ORDER by employee_id,leave_date) t3
 GROUP BY group1) t4 on FIND_IN_SET (t2.leave_request_id ,t4.leave_request_id)
 GROUP BY t2.Group1,t2.leave_request_id
 ORDER BY employee_id,min_applied_date;

Delivers you this result

employee_id     min_applied_date    max_applied_date leave_consec_length  ctual_consect_length
2               2019-10-01          2019-10-03        3                   3
2               2019-10-08          2019-10-08        1                   1
3               2019-10-14          2019-10-14        1                   4
3               2019-10-15          2019-10-15        1                   4
3               2019-10-16          2019-10-16        1                   4
3               2019-10-17          2019-10-17        1                   4
5               2019-09-30          2019-10-01        2                   2
8               2019-10-01          2019-10-01        1                   1

new dbfiddle example https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=4a3f5c1f8070631771a52a195d9f4f55

t2 gets you all the data that you want + leaveconsec_length.

t4 gets the actual consect length days

Edit: For such algorithms to work they have to be sorted correctly



来源:https://stackoverflow.com/questions/58341775/get-count-of-continuous-dates-in-mysql

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!