我需要计算各种员工的病假期限。如果两个病假之间的间隔时间少于28天,那么它们被视为一个时期,因此病假的总持续时间是病假的当前天数+之前的病假总天数。我最后得到了下表:
Key- Start date- End date- Duration in days- Duration of last sickleave- Less the 28 days-
0001 01-01-2015 14-01-2015 13 0 Yes
0001 03-03-2015 19-03-2015 16 13 No
0001 27-05-2015 28-05-2015 1 16 No
0001 18-08-2015 31-08-2015 13 1 No
0001 24-09-2015 05-10-2015 11 13 Yes
0001 21-10-2015 29-10-2015 8 11 Yes
0001 05-11-2015 09-11-2015 4 8 Yes
0001 07-12-2015 08-12-2015 1 4 No
0001 21-12-2015 28-12-2015 7 1 Yes
0001 12-01-2016 18-01-2016 6 7 Yes
0001 08-02-2016 29-02-2016 21 6 Yes
我想最终得到这张表:
Key- Start date- End date- Duration in days- Duration of last sickleave- Less the 28 days- Total number of days-
0001 01-01-2015 14-01-2015 13 0 Yes 13
0001 03-03-2015 19-03-2015 16 13 No 16
0001 27-05-2015 28-05-2015 1 16 No 1
0001 18-08-2015 31-08-2015 13 1 No 13
0001 24-09-2015 05-10-2015 11 13 Yes 24
0001 21-10-2015 29-10-2015 8 11 Yes 32
0001 05-11-2015 09-11-2015 4 8 Yes 36
0001 07-12-2015 08-12-2015 1 4 No 1
0001 21-12-2015 28-12-2015 7 1 Yes 8
0001 12-01-2016 18-01-2016 6 7 Yes 14
0001 08-02-2016 29-02-2016 21 6 Yes 35
如何在SQL中实现这一点(使用Oracle数据库)?因此,当'少于28天' ='是'和'少于28天'在上一行中是'是',然后'总天数' ='总天数' +'最后一次镰刀的持续时间'否则'总天数' ='持续时间以天为单位'
答案 0 :(得分:2)
不是试图将之前的疾病日添加到当前的疾病持续时间,为什么不只是做一个滚动的总和呢?
WITH your_table AS (SELECT '0001' key_, to_date('01-01-2015', 'dd-mm-yyyy') start_date, to_date('14-01-2015', 'dd-mm-yyyy') end_date, 13 duration_in_days, 0 duration_of_last_sickleave, 'Yes' less_than_28_days FROM dual UNION ALL
SELECT '0001' key_, to_date('03-03-2015', 'dd-mm-yyyy') start_date, to_date('19-03-2015', 'dd-mm-yyyy') end_date, 16 duration_in_days, 13 duration_of_last_sickleave, 'No' less_than_28_days FROM dual UNION ALL
SELECT '0001' key_, to_date('27-05-2015', 'dd-mm-yyyy') start_date, to_date('28-05-2015', 'dd-mm-yyyy') end_date, 1 duration_in_days, 16 duration_of_last_sickleave, 'No' less_than_28_days FROM dual UNION ALL
SELECT '0001' key_, to_date('18-08-2015', 'dd-mm-yyyy') start_date, to_date('31-08-2015', 'dd-mm-yyyy') end_date, 13 duration_in_days, 1 duration_of_last_sickleave, 'No' less_than_28_days FROM dual UNION ALL
SELECT '0001' key_, to_date('24-09-2015', 'dd-mm-yyyy') start_date, to_date('05-10-2015', 'dd-mm-yyyy') end_date, 11 duration_in_days, 13 duration_of_last_sickleave, 'Yes' less_than_28_days FROM dual UNION ALL
SELECT '0001' key_, to_date('24-10-2015', 'dd-mm-yyyy') start_date, to_date('29-10-2015', 'dd-mm-yyyy') end_date, 8 duration_in_days, 11 duration_of_last_sickleave, 'Yes' less_than_28_days FROM dual UNION ALL
SELECT '0001' key_, to_date('05-11-2015', 'dd-mm-yyyy') start_date, to_date('09-11-2015', 'dd-mm-yyyy') end_date, 4 duration_in_days, 8 duration_of_last_sickleave, 'Yes' less_than_28_days FROM dual UNION ALL
SELECT '0001' key_, to_date('07-12-2015', 'dd-mm-yyyy') start_date, to_date('08-12-2015', 'dd-mm-yyyy') end_date, 1 duration_in_days, 4 duration_of_last_sickleave, 'No' less_than_28_days FROM dual UNION ALL
SELECT '0001' key_, to_date('21-12-2015', 'dd-mm-yyyy') start_date, to_date('28-12-2015', 'dd-mm-yyyy') end_date, 7 duration_in_days, 1 duration_of_last_sickleave, 'Yes' less_than_28_days FROM dual UNION ALL
SELECT '0001' key_, to_date('12-01-2016', 'dd-mm-yyyy') start_date, to_date('18-01-2016', 'dd-mm-yyyy') end_date, 6 duration_in_days, 7 duration_of_last_sickleave, 'Yes' less_than_28_days FROM dual UNION ALL
SELECT '0001' key_, to_date('08-02-2016', 'dd-mm-yyyy') start_date, to_date('29-03-2016', 'dd-mm-yyyy') end_date, 21 duration_in_days, 6 duration_of_last_sickleave, 'Yes' less_than_28_days FROM dual),
identify_sickness_start AS (SELECT key_,
start_date,
end_date,
duration_in_days,
duration_of_last_sickleave,
less_than_28_days,
CASE WHEN start_date - LAG(end_date, 1, start_date - 30) OVER (PARTITION BY key_ ORDER BY start_date) >= 28 THEN 1 ELSE 0 END new_sickness_period
FROM your_table),
calc_sickness_groups AS (SELECT key_,
start_date,
end_date,
duration_in_days,
duration_of_last_sickleave,
less_than_28_days,
sum(new_sickness_period) OVER (PARTITION BY key_ ORDER BY start_date) grp
FROM identify_sickness_start)
SELECT key_,
start_date,
end_date,
duration_in_days,
duration_of_last_sickleave,
less_than_28_days,
sum(duration_in_days) OVER (PARTITION BY key_, grp ORDER BY start_date) total_number_of_days
FROM calc_sickness_groups
ORDER BY key_, start_date;
KEY_ START_DATE END_DATE DURATION_IN_DAYS DURATION_OF_LAST_SICKLEAVE LESS_THAN_28_DAYS TOTAL_NUMBER_OF_DAYS
---- ----------- ----------- ---------------- -------------------------- ----------------- --------------------
0001 01/01/2015 14/01/2015 13 0 Yes 13
0001 03/03/2015 19/03/2015 16 13 No 16
0001 27/05/2015 28/05/2015 1 16 No 1
0001 18/08/2015 31/08/2015 13 1 No 13
0001 24/09/2015 05/10/2015 11 13 Yes 24
0001 24/10/2015 29/10/2015 8 11 Yes 32
0001 05/11/2015 09/11/2015 4 8 Yes 36
0001 07/12/2015 08/12/2015 1 4 No 1
0001 21/12/2015 28/12/2015 7 1 Yes 8
0001 12/01/2016 18/01/2016 6 7 Yes 14
0001 08/02/2016 29/03/2016 21 6 Yes 35
这首先确定每个疾病组的开始(每次新的疾病期开始时,输出1;这意味着任何时候一行<=前一行后的28天,我们放1,否则a 0。
然后我们可以在此列中执行运行总和,以计算出同一个疾病组中的行。
最后,我们可以针对每组病态行在duration_in_days列中执行总计。
这意味着您不再需要计算duration_of_last_sickleave和less_than_28_days列(我假设您作为select语句的一部分而不是作为表的一部分?),因为它们不再是必需的,至少不是计算总天数!