问题
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