
本文介绍一种简洁可靠的 sql 方法,利用 not in 子查询联动 available_week(周可用性)和 available_day(日异常状态)两张表,排除休假或病假员工,准确返回某日某时段仍处于正常工作状态的员工编号。
本文介绍一种简洁可靠的 sql 方法,利用 not in 子查询联动 available_week(周可用性)和 available_day(日异常状态)两张表,排除休假或病假员工,准确返回某日某时段仍处于正常工作状态的员工编号。
在实际考勤或排班系统中,员工的常规工作安排通常按周定义(如“周一 8:00–17:00 正常出勤”),而临时变动(如请假、病假、调休)则按日记录。这种分离式设计提升了数据灵活性,但也给实时查询带来挑战:仅查周表会遗漏当日异常;仅查日表又无法覆盖未显式记录的“默认可用”员工。
要解决这一问题,核心逻辑是:
✅ 先从 available_week 中获取所有本应于目标时段(如“周一 8 点”)工作的员工;
❌ 再从中剔除那些在 available_day 中被明确标记为不可用(state = 0)的员工——且该记录的日期需严格匹配查询日。
以下为推荐的 SQL 实现(兼容 mysql、postgresql、SQL Server 等主流数据库):
SELECT short FROM available_week WHERE day = 1 AND hour = 8 AND short NOT IN ( SELECT short FROM available_day WHERE state = 0 AND day = '2022-04-09' );
? 关键说明:
✅ 正确执行前提:
- 两张表的 short 字段类型与字符集完全一致(避免隐式转换失败);
- available_day 中仅记录异常状态(state = 0),正常日不插入记录(即“无记录 = 默认可用”);
- 时间粒度对齐:available_week.hour 应代表开始小时(如 8 表示 08:00–08:59),且 available_day.time 含义一致。
⚠️ 进阶建议(高可靠性场景):
若数据量大或存在 NULL 风险,推荐使用 NOT EXISTS 替代 NOT IN:
SELECT w.short FROM available_week w WHERE w.day = 1 AND w.hour = 8 AND NOT EXISTS ( SELECT 1 FROM available_day d WHERE d.short = w.short AND d.state = 0 AND d.day = '2022-04-09' );
该写法不受 NULL 影响,且可借助 (short, day) 复合索引显著提升性能。
综上,此方案以最小改动实现跨表状态融合,兼顾可读性、可维护性与生产可用性,是处理“默认规则 + 日级例外”类业务查询的经典范式。