校招算法笔面试 | SQL笔试面试编程题-获取所有非manager的员工emp_no

题目

题目链接

我们需要从员工表中找出所有没有在部门领导表中出现的员工编号。我们要做的事情如下:

1. 确定总体问题

这道题目要求我们找出所有不是部门领导的员工编号。我们需要从员工表和部门领导表中提取数据,通过员工编号进行左连接,以确保即使没有部门信息的员工也能被列出,然后筛选出那些没有部门领导记录的员工。

2. 分析关键问题
  • 左连接表:将employeesdept_manager表进行左连接,以便获取每个员工的部门领导信息。
  • 筛选非部门领导的员工:找出那些没有部门领导记录的员工。
3. 解决每个关键问题的代码及讲解
步骤1:左连接表

我们使用LEFT JOINemployeesdept_manager表连接起来:

from
    employees e
    left join dept_manager d on e.emp_no = d.emp_no
  • LEFT JOIN dept_manager d ON e.emp_no = d.emp_no:通过员工编号进行左连接,以确保即使没有部门信息的员工也能被列出,左连接之后空着的dept_no会默认为null,即员工数据行。
步骤2:筛选非部门领导的员工

我们使用WHERE子句筛选出没有部门领导记录的员工:

where 
    dept_no is null
  • WHERE dept_no IS NULL:筛选出那些没有在部门领导表中出现的员工。

完整代码

select
    e.emp_no
from
    employees e
    left join dept_manager d on e.emp_no = d.emp_no
where 
    dept_no is null;
你当前的 SQL 查询中,通过 `CASE` 语句计算了外派人员的**预计退休时间(overseas_plan_retire_date)**: ```sql CASE WHEN dce.emp_sex_code = 'M' THEN dce.birth_date + interval '60 year' WHEN dce.emp_sex_code = 'F' THEN dce.birth_date + interval '55 year' END AS overseas_plan_retire_date ``` 现在你的需求是:**修改为“男女法定退休年龄每四个月延迟一个月”**。这意味着退休年龄将逐步延迟,而不是固定为 60(男)和 55(女)岁。 --- ### ✅ 需求理解 > “每四个月延迟一个月” 是指: - 每过 4 个月,法定退休年龄就推迟 1 个月。 - 这是一种渐进式延迟退休政策,通常从某个基准日期开始计算延迟时长。 例如: - 如果某男性原定 60 岁退休,但由于他出生较晚或政策实施时间靠后,需要根据其出生年月或政策起始日之后的时间长度来累计“延迟月数”。 但注意:该表述常用于 **基于政策实施起始日以来的时间推移来计算延迟月数**,而不是直接与出生日期挂钩。 所以我们需要明确一个关键点: --- ### 🎯 明确前提假设(合理设定) 由于你的原始数据只有员工性别和出生日期,没有入职时间、岗位类型等其他信息,我们做如下常见假设: > 延迟退休政策从 **2025年1月1日** 起正式实施, > 对于在此日期之后达到原定退休年龄的人群,每超过4个月,退休年龄延后1个月。 即: - 男性原退休年龄:60 岁 - 女性原退休年龄:55 岁 - 政策起始日:`DATE '2025-01-01'` - 若某人按原规定应在 2025 年后退休,则超出部分每满 4 个月,延迟 1 个月。 --- ### ✅ 修改逻辑:动态计算延迟月数 #### 步骤说明: 1. 计算员工原本应退休的日期(未延迟): - 男性:出生日 + 60 年 - 女性:出生日 + 55 年 2. 判断这个“原定退休日期”是否在政策起始日(2025-01-01)之后? 3. 如果是,则计算超出多少个月。 4. 每超过 4 个月,延迟 1 个月(向下取整除法)。 5. 最终退休日期 = 原退休日期 + 延迟月数 --- ### ✅ 修改后的 SQL(PostgreSQL 风格) ```sql WITH temp AS ( SELECT dceriz.long_uuid -- 主键ID ,dceriz.emp_id -- 员工id ,dceriz.emp_account -- 员工账号 ,dceriz.emp_name -- 员工姓名 ,dce.emp_sex_code -- 员工性别 ,dce.birth_date -- 员工出生日期 ,dceriz.employer -- 所在单位 ,dceriz.job_level_name -- 职级 ,dceriz.position -- 从事工作或担任职务 ,dceriz.start_date -- 开始时间 ,dceriz.end_date -- 结束时间 ,dceriz.oversid_flag -- 是否海外工作经历 ,dceriz.employer_country_code -- 员工工作单位所在国家或地区编码 -- 新增:动态延迟退休计算 ,( CASE WHEN dce.emp_sex_code = 'M' THEN dce.birth_date + INTERVAL '60 years' WHEN dce.emp_sex_code = 'F' THEN dce.birth_date + INTERVAL '55 years' ELSE NULL END )::DATE AS base_retire_date -- 原定退休日期 ,( CASE WHEN dce.emp_sex_code = 'M' THEN dce.birth_date + INTERVAL '60 years' WHEN dce.emp_sex_code = 'F' THEN dce.birth_date + INTERVAL '55 years' ELSE NULL END + -- 加上延迟月份 MAKE_INTERVAL( months => GREATEST( FLOOR( EXTRACT(EPOCH FROM ( (CASE WHEN dce.emp_sex_code = 'M' THEN dce.birth_date + INTERVAL '60 years' WHEN dce.emp_sex_code = 'F' THEN dce.birth_date + INTERVAL '55 years' END) - DATE '2025-01-01' )) / (30 * 24 * 60 * 60) -- 转成天数再转月(近似) ) / 4 )::INT, 0) ) )::DATE AS overseas_plan_retire_date -- 外派人员预计退休时间(含延迟) FROM hr_dw.dw_co_em_resume_info_zyhy dceriz INNER JOIN ( SELECT DISTINCT dceri.emp_id ,dcebi.emp_sex_code ,dcebi.birth_date FROM hr_dw.dw_co_em_resume_info_zyhy dceri INNER JOIN ( SELECT DISTINCT emp_id, emp_sex_code, birth_date FROM hr_dw.dw_co_em_basic_info WHERE emp_status_code = 'A' -- 在职 ) dcebi ON dcebi.emp_id = dceri.emp_id WHERE dceri.end_date >= CURRENT_DATE AND dceri.employer_country_code <> 'CHN' -- 外派在岗 ) dce ON dceriz.emp_id = dce.emp_id WHERE dceriz.employer_country_code <> 'CHN' ) -- 可选:进一步筛选仍在职且未退休者 SELECT * FROM temp; ``` --- ### 🔍 代码解释 | 片段 | 解释 | |------|------| | `base_retire_date` | 先计算原始退休日期(无延迟),便于调试 | | `EXTRACT(EPOCH FROM (...))` | 将两个日期之差转为秒数 | | `/ (30 * 86400)` | 约等于将秒数转为“月数”(按每月30天估算) | | `/ 4` 后 `FLOOR(...)` | 每4个月延迟1个月 → 总延迟月数 | | `MAKE_INTERVAL(months => ...)` | 安全地增加指定月数 | | `GREATEST(..., 0)` | 防止负值(即早于2025年退休的人不延迟) | > ⚠️ 注意:这里使用的是 **近似月数计算**,更精确的做法可以使用 `AGE()` 或逐月判断,但在大数据量下性能更好。 --- ### ✅ 示例演示 假设一位男性出生于 `1965-01-01`: - 原退休日期:`2025-01-01` - 超出政策起点:刚好0天 → 延迟 0 个月 - 若出生晚4个月 → `1965-05-01` → 原退休日 `2025-05-01` - 超出:5个月 → `floor(5/4)=1` → 延迟1个月 → 实际退休 `2025-06-01` --- ### ✅ 更高精度版本(可选优化) 如果你希望更准确处理月份差异(避免用天数估算),可以用: ```sql months_after_policy AS ( EXTRACT(YEAR FROM AGE( CASE WHEN emp_sex_code = 'M' THEN birth_date + INTERVAL '60 years' ELSE birth_date + INTERVAL '55 years' END, DATE '2025-01-01' )) * 12 + EXTRACT(MONTH FROM AGE( CASE WHEN emp_sex_code = 'M' THEN birth_date + INTERVAL '60 years' ELSE birth_date + INTERVAL '55 years' END, DATE '2025-01-01' )) ) ``` 然后延迟月数 = `GREATEST(FLOOR(months_after_policy / 4), 0)` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值