实际在职人数

SQL统计实际在职人数

问题 分两种情况:

  1. 每月在职人数, 只要本月在职, 就算做1人在职
  2. 本月在职几天, 在职人数=在职天数/本月天数

情况一:

问题: 有员工信息表, 统计近 3个月, 每个月实际在职人数(只要本月有在职,不管在职几天,就算做1人在职)
 员工信息表: user_id(用户id), start_date(入职时间), end_date(离职时间,null代表未离职)
 日期月份表: mt(月份)
1. 数据准备
-- 数据准备
WITH t_emp_info AS ( -- 员工信息表
SELECT * FROM (
  VALUES    (1001, '2023-08-14', '2023-09-23'),
            (1002, '2023-09-10', '2023-10-25'),
            (1003, '2023-09-16', '2023-12-15'),
            (1004, '2023-09-21', NULL ),
            (1005, '2023-10-12', '2023-11-21'),
            (1006, '2023-10-16', '2023-10-28'),
            (1007, '2023-10-20', '2023-12-02'),
            (1008, '2023-10-26', '2023-11-26'),
            (1009, '2023-10-28', NULL ),
            (1010, '2023-11-02', '2023-11-26'),
            (1011, '2023-11-06', '2023-12-16'),
            (1012, '2023-11-12', '2023-12-25')
) AS table_name(user_id, start_date, end_date)
)

, t_mt AS ( -- 日期月份表
SELECT * FROM (
  VALUES
    ('2023-09'), ('2023-10'), ('2023-11')
) AS table_name(mt)
)
2. 代码实现
-- 1. 关联,月份在职人员情况
SELECT 
    /*+ mapjoin(b) */  -- MC 运行环境要求, 没有使用 MapJoin 不能使用笛卡尔积, join 条件不能使用范围类型
      a.mt, b.user_id, start_date, end_date
FROM t_mt a
LEFT JOIN t_emp_info b 
ON  a.mt >= DATE_FORMAT(b.start_date, 'yyyy-MM') AND a.mt <= DATE_FORMAT(NVL(b.end_date, '2023-11-30'), 'yyyy-MM')
 ;
mtuser_idstart_dateend_date
2023-0910012023-08-142023-09-23
2023-0910022023-09-102023-10-25
2023-0910032023-09-162023-12-15
2023-0910042023-09-21\N
2023-1010022023-09-102023-10-25
2023-1010032023-09-162023-12-15
2023-1010042023-09-21\N
2023-1010052023-10-122023-11-21
2023-1010062023-10-162023-10-28
2023-1010072023-10-202023-12-02
-- 2. 统计每月在职人数
SELECT 
    mt, COUNT(DISTINCT user_id) AS user_ct
FROM (
    SELECT 
        /*+ mapjoin(b) */  -- MC 运行环境要求, 没有使用 MapJoin 不能使用笛卡尔积, join 条件不能使用范围类型
          a.mt, b.user_id, start_date, end_date
    FROM t_mt a
    LEFT JOIN t_emp_info b 
    ON  a.mt >= DATE_FORMAT(b.start_date, 'yyyy-MM') AND a.mt <= DATE_FORMAT(NVL(b.end_date, '2023-11-30'), 'yyyy-MM')
) c 
GROUP BY mt
;
mtuser_ct
2023-094
2023-108
2023-119

情况二:

问题: 有员工信息表, 统计近 3个月, 每个月实际在职人数( 在职人数=在职天数/本月天数 )
 员工信息表: user_id(用户id), start_date(入职时间), end_date(离职时间,null代表未离职)
 日期表: dt_date(日期)
1. 数据准备
WITH t_emp_info AS ( -- 员工信息表
SELECT * FROM (
  VALUES    (1001, '2023-08-14', '2023-09-23'),
            (1002, '2023-09-10', '2023-10-25'),
            (1003, '2023-09-16', '2023-12-15'),
            (1004, '2023-09-21', NULL ),
            (1005, '2023-10-12', '2023-11-21'),
            (1006, '2023-10-16', '2023-10-28'),
            (1007, '2023-10-20', '2023-12-02'),
            (1008, '2023-10-26', '2023-11-26'),
            (1009, '2023-10-28', NULL ),
            (1010, '2023-11-02', '2023-11-26'),
            (1011, '2023-11-06', '2023-12-16'),
            (1012, '2023-11-12', '2023-12-25')
) AS table_name(user_id, start_date, end_date)
)

, t_dt AS ( -- 日期表
SELECT * FROM (
  VALUES
                      ('2023-09-10'), ('2023-09-20')
    , ('2023-09-01'), ('2023-09-11'), ('2023-09-21')
    , ('2023-09-02'), ('2023-09-12'), ('2023-09-22')
    , ('2023-09-03'), ('2023-09-13'), ('2023-09-23')
    , ('2023-09-04'), ('2023-09-14'), ('2023-09-24')
    , ('2023-09-05'), ('2023-09-15'), ('2023-09-25')
    , ('2023-09-06'), ('2023-09-16'), ('2023-09-26')
    , ('2023-09-07'), ('2023-09-17'), ('2023-09-27')
    , ('2023-09-08'), ('2023-09-18'), ('2023-09-28')
    , ('2023-09-09'), ('2023-09-19'), ('2023-09-29')
    , ('2023-09-30'), ('2023-10-10'), ('2023-10-20')
    , ('2023-10-01'), ('2023-10-11'), ('2023-10-21')
    , ('2023-10-02'), ('2023-10-12'), ('2023-10-22')
    , ('2023-10-03'), ('2023-10-13'), ('2023-10-23')
    , ('2023-10-04'), ('2023-10-14'), ('2023-10-24')
    , ('2023-10-05'), ('2023-10-15'), ('2023-10-25')
    , ('2023-10-06'), ('2023-10-16'), ('2023-10-26')
    , ('2023-10-07'), ('2023-10-17'), ('2023-10-27')
    , ('2023-10-08'), ('2023-10-18'), ('2023-10-28')
    , ('2023-10-09'), ('2023-10-19'), ('2023-10-29')
    , ('2023-10-30'), ('2023-11-10'), ('2023-11-20')
    , ('2023-11-01'), ('2023-11-11'), ('2023-11-21')
    , ('2023-11-02'), ('2023-11-12'), ('2023-11-22')
    , ('2023-11-03'), ('2023-11-13'), ('2023-11-23')
    , ('2023-11-04'), ('2023-11-14'), ('2023-11-24')
    , ('2023-11-05'), ('2023-11-15'), ('2023-11-25')
    , ('2023-11-06'), ('2023-11-16'), ('2023-11-26')
    , ('2023-11-07'), ('2023-11-17'), ('2023-11-27')
    , ('2023-11-08'), ('2023-11-18'), ('2023-11-28')
    , ('2023-11-09'), ('2023-11-19'), ('2023-11-29')
    , ('2023-11-30'), ('2023-10-31')
) AS table_name(dt_date)
)
2. 代码实现
-- 1. 日期和用户关联
SELECT 
    /*+ mapjoin(b) */  -- MC 运行环境要求, 没有使用 MapJoin 不能使用笛卡尔积, join 条件不能使用范围类型
    a.dt_date, b.user_id, b.start_date, b.end_date
FROM t_dt a 
LEFT JOIN t_emp_info b  
ON a.dt_date BETWEEN b.start_date AND NVL(b.end_date, '2023-11-30') 
;
dt_dateuser_idstart_dateend_date
2023-09-1010012023-08-142023-09-23
2023-09-2010012023-08-142023-09-23
2023-09-0110012023-08-142023-09-23
2023-09-1110012023-08-142023-09-23
2023-09-2110012023-08-142023-09-23
2023-09-0210012023-08-142023-09-23
2023-09-1210012023-08-142023-09-23
2023-09-2210012023-08-142023-09-23
2023-09-0310012023-08-142023-09-23
2023-09-1310012023-08-142023-09-23
2023-09-2310012023-08-142023-09-23
2023-09-0410012023-08-142023-09-23
-- 2. 统计每月实际在职人数
SELECT 
      DATE_FORMAT(dt_date, 'yyyy-MM') AS mt -- 月份
    , COUNT(user_id) AS user_day_ct -- 在职人天数(本月所有在职人, 总共在职多少天)
    , COUNT(DISTINCT dt_date) AS mt_ct -- 本月天数
    , ROUND(COUNT(user_id) / COUNT(DISTINCT dt_date) , 3) AS user_ct 
FROM (
    SELECT 
        /*+ mapjoin(b) */  -- MC 运行环境要求, 没有使用 MapJoin 不能使用笛卡尔积, join 条件不能使用范围类型
        a.dt_date, b.user_id, b.start_date, b.end_date
    FROM t_dt a 
    LEFT JOIN t_emp_info b  
    ON a.dt_date BETWEEN b.start_date AND NVL(b.end_date, '2023-11-30') 
) c
GROUP BY DATE_FORMAT(dt_date, 'yyyy-MM')
;

-- 2. 方法二: 笛卡尔积
SELECT 
      DATE_FORMAT(dt_date, 'yyyy-MM') AS mt -- 月份
    , COUNT(user_id) AS user_day_ct -- 在职人天数(本月所有在职人, 总共在职多少天)
    , COUNT(DISTINCT dt_date) AS mt_ct -- 本月天数
    , ROUND(COUNT(user_id) / COUNT(DISTINCT dt_date) , 3) AS user_ct 
FROM (
    SELECT -- join 时使用 笛卡尔积, 下游进行过滤
        /*+ mapjoin(b) */  -- MC 运行环境要求, 没有使用 MapJoin 不能使用笛卡尔积, join 条件不能使用范围类型
        a.dt_date, b.user_id, b.start_date, b.end_date
    FROM t_dt a 
    LEFT JOIN t_emp_info b  
) c
WHERE dt_date BETWEEN start_date AND NVL(end_date, '2023-11-30') 
GROUP BY DATE_FORMAT(dt_date, 'yyyy-MM')
;
mtuser_day_ctmt_ctuser_ct
2023-0969302.3
2023-10142314.581
2023-11236307.867
end
  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值