50. 员工在职人数问题

文章目录

        • 题目需求
        • 思路一
        • 实现一
        • 思路二
        • 实现二
        • 题目来源

题目需求

现有用户表(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 (在职人数)
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

你可能感兴趣的:(#,HQL题目,sql,hive,数据库,大数据,数据仓库)