50. 员工在职人数问题

题目需求

现有用户表(emp)如下。

id (员工id)en_dt (入职日期)le_dt(离职日期)
10012020-01-02null
10022020-01-022020-03-05
10032020-02-022020-02-15
10042020-02-122020-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)> (在职人数)
11.94
23.62
32.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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dataer__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值