如何通过 SQL 联查周表与日表,精准筛选指定日期/时段的可用员工

2次阅读

如何通过 SQL 联查周表与日表,精准筛选指定日期/时段的可用员工

本文介绍一种简洁可靠的 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 实现(兼容 mysqlpostgresql、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'   );

? 关键说明

  • day = 1 表示星期一(按 ISO 标准,1=Monday;请根据实际数据校验取值逻辑);
  • ‘2022-04-09’ 是目标查询日期,必须与 available_day.day 字段格式一致(示例中为 YYYY-MM-DD 字符串,若字段为 date 类型则无需引号);
  • 使用 NOT IN 而非 LEFT JOIN … IS NULL,语义更直观,性能在中小数据量下表现良好;但需注意:若子查询返回 NULL 值,NOT IN 整体结果为空(这是 SQL 三值逻辑特性),因此务必确保 available_day.short 列非空,或改用 NOT EXISTS 做更健壮处理(见进阶建议)。

正确执行前提

  • 两张表的 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) 复合索引显著提升性能。

综上,此方案以最小改动实现跨表状态融合,兼顾可读性、可维护性与生产可用性,是处理“默认规则 + 日级例外”类业务查询的经典范式。

text=ZqhQzanResources