题目需求
现有用户表(emp)如下。
id (员工id) | en_dt (入职日期) | le_dt(离职日期) |
---|---|---|
1001 | 2020-01-02 | null |
1002 | 2020-01-02 | 2020-03-05 |
1003 | 2020-02-02 | 2020-02-15 |
1004 | 2020-02-12 | 2020-03-08 |
日历表(cal) 如下:
dt (日期) |
---|
2020-01-01 |
2020-01-02 |
2020-01-03 |
… |
统计2020年前三个月实际在职员工数量(只统计2020-03-31之前)。
如果1个月在职天数只有1天,数量计算方式:1/当月天数。
如果一个月只有一天的话,只算30分之1个人
期望结果如下(截取部分):
mnt (月份) | ps <decimal(16,2)> (在职人数) |
---|---|
1 | 1.94 |
2 | 3.62 |
3 | 2.23 |
思路一
关联得出每个人在职的记录。
实现一
-- 思路一(from 网友): 关联得出每个人在职的记录
SELECT months mth,
cast(emp_days / days as DECIMAL(16, 2)) ps
from (
SELECT month(dt) months,
-- 所有人在职天数
count(id) emp_days,
-- 每个月的天数
count(DISTINCT cal.dt) days
from (
SELECT id,
en_dt,
nvl(le_dt, '2020-03-31') le_dt
from emp
) emp
right join cal
on cal.dt >= emp.en_dt
and cal.dt <= emp.le_dt
group by month(dt)
) t1;
思路二
计算每天的员工变动情况。
前提: 所有员工入职时间 >= 2020-01-01
实现二
-- 实现二: from 网友
WITH tmp as (
-- 人员变动情况
SELECT dt,
sum(flag) flag
from (
-- 入职: 标记 flag=1
SELECT en_dt dt,
1 flag
from emp
UNION ALL
(
-- 离职: 标记 flag=-1
-- 员工离职: 离职当天算作在职员工
SELECT if(le_dt is null, '2020-04-01', date_add(le_dt, 1)) dt,
-1 flag
from emp
)
) t1
group by dt
)
SELECT m mth,
-- 当 c 不是 group by 分组字段时,使用 max(c) 可以取出
CAST(sum(emp_count) / max(c) as decimal(16, 2)) ps
from (
SELECT MONTH(dt) m,
emp_count,
-- 计算每月的天数
count(1) OVER (PARTITION by MONTH(dt)) c
from (
-- 计算每天的在职人数
SELECT cal.dt,
sum(nvl(flag, 0)) over (ORDER by cal.dt) emp_count
from cal
LEFT JOIN tmp
on cal.dt = tmp.dt
) t1
) t2
GROUP by m;
题目来源
http://practice.atguigu.cn/#/question/50/desc?qType=SQL