ITPub博客

首页 > 数据库 > 数据库开发技术 > SQL 案例分析:员工考勤记录

SQL 案例分析:员工考勤记录

原创 数据库开发技术 作者:BUAA_dxy 时间:2021-12-29 21:09:36 0 删除 编辑

假设公司规定周一到周五(节假日除外)每天早上九点上班,下午六点下班,上下班都需要打卡。员工的打卡记录信息存储在attendance表中,同时日历信息存储calendar表中,这两个表的创建脚本如下:

-- 创建日历表calendarCREATE TABLE calendar(  id             INTEGER NOT NULL PRIMARY KEY, -- 日历编号  calendar_date  DATE NOT NULL UNIQUE, -- 日历日期  calendar_year  INTEGER NOT NULL, -- 日历年  calendar_month INTEGER NOT NULL, -- 日历月  calendar_day   INTEGER NOT NULL, -- 日历日  is_work_day    VARCHAR(1) DEFAULT 'Y' NOT NULL -- 是否工作日);
-- 创建考勤记录表attendance-- Oracle、MySQL、PostgreSQL 以及 SQLiteCREATE TABLE attendance( id INTEGER NOT NULL PRIMARY KEY, -- 考勤记录编号 check_date DATE NOT NULL, -- 考勤日期 emp_id INTEGER NOT NULL, -- 员工编号 clock_in TIMESTAMP, -- 上班打卡时间 clock_out TIMESTAMP, -- 下班打卡时间 CONSTRAINT uk_attendance UNIQUE (check_date, emp_id));-- SQL ServerCREATE TABLE attendance( id INTEGER NOT NULL PRIMARY KEY, -- 考勤记录编号 check_date DATE NOT NULL, -- 考勤日期 emp_id INTEGER NOT NULL, -- 员工编号 clock_in DATETIME2, -- 上班打卡时间 clock_out DATETIME2, -- 下班打卡时间 CONSTRAINT uk_attendance UNIQUE (check_date, emp_id));

以下是attendance表中的部分示例数据:

id|check_date|emp_id|clock_in           |clock_out          --|----------|------|-------------------|------------------- 1|2021-01-04|     1|2021-01-04 08:34:02|2021-01-04 18:33:11 2|2021-01-04|     2|2021-01-04 08:10:31|2021-01-04 19:11:59 3|2021-01-04|     3|2021-01-04 08:54:08|2021-01-04 18:27:21...

其中,check_date是考勤日期,emp_id是员工编号,clock_in和clock_out分别是上班和下班打卡时间。

以下是calendar表中的部分示例数据:

 id|calendar_date|calendar_year|calendar_month|calendar_day|is_work_day---|-------------|-------------|--------------|------------|-----------  1| 2021-01-01|         2021|             1|           1|N           2| 2021-01-02|         2021|             1|           2|N           3| 2021-01-03|         2021|             1|           3|N         ...

其中canlendar_date是日历日期,canlendar_year、calendar_month、calendar_day分别是日历日期对应的年、月、日,is_work_day表示是否为工作日。

假如HR想要统计2021年1月份的员工缺勤记录,请问如何通过SQL查询相关记录?

首先,我们应该找出所有员工2021年1月份应该出勤的日期信息。这个数据可以通过日历表和员工表的交叉连接实现:

SELECT c.calendar_date, e.emp_nameFROM calendar cCROSS JOIN employee eWHERE c.calendar_year = 2021AND c.calendar_month = 1AND c.is_work_day = 'Y';

查询返回的结果如下。

calendar_date|emp_name-------------|--------   2021-01-04|刘备        2021-01-04|关羽        2021-01-04|张飞     ...

如果某个员工在工作日没有打卡,attendance表中就会缺少相应的记录,表示缺勤。如果只有上班打卡,没有下班打卡,也当作缺勤处理。如果员工的上班打卡时间晚于9点,表示迟到。如果员工的下班打卡时间早于下午6点,表示早退。因此,我们可以将上面的查询结果和考勤表中的数据进行左外连接:

-- Oracle、MySQL以及PostgreSQLSELECT c.calendar_date, e.emp_name, a.clock_in, a.clock_outFROM calendar cCROSS JOINemployee eLEFT JOINattendance aON (a.check_date = c.calendar_date AND a.emp_id = e.emp_id)WHERE c.calendar_year = 2021 AND c.calendar_month = 1AND c.is_work_day = 'Y'AND (a.id IS NULL     OR EXTRACT(hour FROMa.clock_in) >= 9     OR EXTRACT(hour FROMa.clock_out) < 18     OR a.clock_out IS NULL)ORDER BY c.calendar_date;

我们在左外连接中使用考勤日期和员工编号作为连接条件,同时在WHERE条件中增加了一个AND复合条件,返回了缺勤、迟到以及早退的数据。查询返回的结果如下。

calendar_date|emp_name|clock_in            |clock_out         -------------|--------|-------------------|-------------------   2021-01-05|简雍     |                   |                     2021-01-11|关平     |                   |                     2021-01-13|周仓     |2021-01-13 08:34:28|                     2021-01-14|简雍     |                   |                      2021-01-19|孙乾     |2021-01-19 08:14:17|2021-01-19 17:44:08   ...

只要clock_out字段为空就是缺勤,clock_in时间晚于9点的数据就是迟到,clock_out时间早于18点的数据就是早退。

如果使用Microsoft SQL Server,我们需要将查询中的EXTRACT函数替换为DATEPART函数。如果使用SQLite,我们需要将查询中的EXTRACT函数替换为STRFTIME函数,再利用CAST函数将其转换为整数。这些函数的使用可以参考本书第3章。

我们还可以进一步利用搜索CASE表达式将查询结果进行转换显示:

-- Oracle、MySQL以及PostgreSQLSELECT c.calendar_date AS "考勤日期", e.emp_name AS "员工姓名",       CASE         WHEN a.clock_out ISNULL THEN '缺勤'         WHEN EXTRACT(hourFROM a.clock_in) >= 9 THEN '迟到'         ELSE '早退'       END AS "考勤状态"FROM calendar cCROSS JOIN employee eLEFT JOIN attendance aON (a.check_date = c.calendar_date AND a.emp_id = e.emp_id)WHERE c.calendar_year = 2021 AND c.calendar_month = 1AND c.is_work_day = 'Y'AND (a.id IS NULL     OR EXTRACT(hour FROM a.clock_in) >= 9     OR EXTRACT(hour FROMa.clock_out) < 18     OR a.clock_out IS NULL)ORDER BY c.calendar_date;

其中CASE表达式可以将打卡时间转换为考勤状态,查询返回的结果如下。

考勤日期   |员工姓名|考勤状态----------|-------|-------2021-01-05|简雍    |缺勤 2021-01-11|关平    |缺勤 2021-01-13|周仓    |缺勤 2021-01-14|简雍    |缺勤 2021-01-19|孙乾    |早退 ...

  以上案例来自图书《SQL编程思想》。

原文作者:SQL编程思想;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论
《SQL编程思想》作者,专注于数据库领域知识的分享。

注册时间:2021-08-26

  • 博文量
    443
  • 访问量
    546960