员工考勤管理系统数据库设计:五张表建表与统计SQL实战
发布时间:2026/10/2 10:46:14来源:尧图网络
简介这份文档面向数据库课程设计、毕业设计或企业考勤系统开发的学习者围绕员工考勤管理场景给出了一套完整的数据库逻辑结构设计方案帮助读者理解从需求分析到表结构落地的全过程。资源包共1个doc文件约57KB内容以数据库设计说明与表结构定义为主适合直接作为课程设计参考或建表依据。文档详细列出了员工基本信息表、部门信息表、考勤类型信息表、员工考勤信息表及用户信息表五张核心表逐字段标注了主键、外键、数据类型与约束并梳理了用户管理、登录鉴权、员工与部门信息增删改查、考勤记录维护、多条件组合查询以及按月按部门统计考勤次数与罚金等九项功能需求。读者可据此快速完成建库建表、理解数据规范化与一致性设计思路并借助附表的统计口径设计查询与报表逻辑。目前已有262人学习下载适合需要落地考勤数据库方案的初、中级开发者参考。1. 从一份 .doc 说起考勤系统数据库设计到底交付了什么很多人拿到「员工考勤管理系统数据库设计.doc」这类资源第一反应是「就一个 Word 文档能有多大用」。我一开始也这么想直到接手一个工厂的考勤模块改造才发现这类文档真正的价值不在排版而在它把五张表的字段、主外键、查询口径和统计报表一次性钉死了。它解决的是「表该怎么建、字段怎么定、统计怎么算」这三件最容易返工的事适合正在做课程设计的学生、要快速搭考勤模块的后端以及需要给现有系统补数据库设计文档的从业者。文档里给出的员工基本信息表、部门信息表、考勤类型信息表、员工考勤信息表和用户信息表基本覆盖了一个中小型考勤系统的数据骨架下面我按能直接落库的顺序把它拆开讲。2. 五张表怎么落地从字段类型到建表语句2.1 先看表结构和字段选型文档里给的是逻辑结构字段名和类型都写清楚了但直接照抄有几个地方会翻车。先把五张表的核心字段列出来对照着看哪些需要改。表名中文名主键关键外键备注book_info员工基本信息表emp_nodep_no → dep_info表名建议改 emp_infodep_info部门信息表dep_no无部门编号 char(3)work_check_categories考勤类型信息表check_no无含罚金字段 fineemp_work_check_info员工考勤信息表bhemp_no → book_info文档未标外键需补users用户信息表bh无密码字段偏短这张表里最值得说的是两个点。第一员工基本信息表叫book_info从字段看明显是「员工信息」被误写成了「book」建表时建议改成emp_info否则后面写 SQL 每次都要愣一下。第二考勤信息表的主键文档写的是bh但摘要里说「员工编号和考勤日期是主键」两处不一致。实际落地时我一般用自增bh做主键再对(emp_no, check_date, check_name)建唯一索引既避免同一天同一类型重复记录又不会因为联合主键导致外键引用变复杂。2.2 建表语句与参数说明下面这套 DDL 是我按文档字段整理并补全约束后的版本MySQL 8.0 可直接执行。字符集统一用 utf8mb4避免员工姓名里有生僻字或少数民族文字时存不进去。-- 部门信息表先建被员工表引用 CREATE TABLE dep_info ( dep_no CHAR(3) NOT NULL COMMENT 部门编号, depName VARCHAR(10) NOT NULL COMMENT 部门名, PRIMARY KEY (dep_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT部门信息表; -- 员工基本信息表文档里叫 book_info这里改为 emp_info CREATE TABLE emp_info ( emp_no VARCHAR(10) NOT NULL COMMENT 员工编号, empName VARCHAR(20) NOT NULL COMMENT 员工名, dep_no VARCHAR(10) DEFAULT NULL COMMENT 所属部门编号, birthday DATETIME DEFAULT NULL COMMENT 出生日期, address VARCHAR(40) DEFAULT NULL COMMENT 住址, hire_date DATETIME DEFAULT NULL COMMENT 雇佣日期, tel VARCHAR(20) DEFAULT NULL COMMENT 联系电话, phote IMAGE DEFAULT NULL COMMENT 员工照片, -- MySQL 不支持 IMAGE PRIMARY KEY (emp_no), KEY idx_dep_no (dep_no), CONSTRAINT fk_emp_dep FOREIGN KEY (dep_no) REFERENCES dep_info (dep_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT员工基本信息表;这里有个必须改的地方phote字段类型写的是IMAGE这是 SQL Server 的类型MySQL 里没有。常见做法是改成VARCHAR(255)存图片路径或者用BLOB存二进制。我一般选前者图片放文件服务器或对象存储数据库只存 URL查询和备份都轻。另外字段名phote是photo的拼写错误建表时顺手改掉不然后面接口命名跟着错一路。-- 考勤类型信息表 CREATE TABLE work_check_categories ( check_no VARCHAR(20) NOT NULL COMMENT 编号, check_name VARCHAR(20) NOT NULL COMMENT 考勤类型, fine NUMERIC(3) DEFAULT 0 COMMENT 罚金, PRIMARY KEY (check_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT考勤类型信息表; -- 员工考勤信息表补上外键和唯一索引 CREATE TABLE emp_work_check_info ( bh VARCHAR(10) NOT NULL COMMENT 编号, emp_no VARCHAR(10) NOT NULL COMMENT 员工编号, check_date DATETIME NOT NULL COMMENT 日期, check_name VARCHAR(20) NOT NULL COMMENT 考勤类型, fine NUMERIC(3) DEFAULT 0 COMMENT 罚金, PRIMARY KEY (bh), UNIQUE KEY uk_emp_date_type (emp_no, check_date, check_name), CONSTRAINT fk_check_emp FOREIGN KEY (emp_no) REFERENCES emp_info (emp_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT员工考勤信息表; -- 用户信息表 CREATE TABLE users ( bh VARCHAR(10) NOT NULL COMMENT 编号, username VARCHAR(20) NOT NULL COMMENT 用户名, user_pwd VARCHAR(10) NOT NULL COMMENT 密码, PRIMARY KEY (bh), UNIQUE KEY uk_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户信息表;参数上重点看三个。fine用NUMERIC(3)只能存 -999 到 999如果罚金可能上千改成NUMERIC(8,2)更稳。user_pwd给VARCHAR(10)太短存明文都不够安全实际项目里至少VARCHAR(64)存哈希值。check_date用DATETIME会带上时分秒做「按月统计」时要用DATE_FORMAT截断如果只关心日期用DATE类型更省心。3. 查询与统计怎么实现把文档里的九条需求翻译成 SQL3.1 员工信息的三类查询文档里员工基本信息查询写了三种按姓名模糊查、按部门查、按雇佣时间段查。这三条对应到 SQL 就是LIKE、等值连接和时间范围组合起来就是动态条件拼接。-- 按姓名模糊 按部门 按雇佣时间段组合查询 SELECT e.emp_no, e.empName, d.depName, e.hire_date, e.tel FROM emp_info e LEFT JOIN dep_info d ON e.dep_no d.dep_no WHERE 1 1 AND e.empName LIKE CONCAT(%, :keyword, %) -- 姓名模糊keyword 为空时不影响 AND (:depNo IS NULL OR e.dep_no :depNo) -- 部门可选 AND (:startDate IS NULL OR e.hire_date :startDate) AND (:endDate IS NULL OR e.hire_date :endDate) ORDER BY e.hire_date DESC;逻辑说明用LEFT JOIN而不是INNER JOIN是因为员工可能还没分配部门内连接会把这些员工直接过滤掉。WHERE 11是动态拼接的常见写法方便后面按需追加条件。参数:keyword传空字符串时LIKE %%匹配全部:depNo传NULL时条件短路这样一套 SQL 覆盖三种查询和它们的组合不用写四五个分支。3.2 考勤统计两张报表的 SQL文档里的付表一和付表二是整个设计的核心产出。付表一是「按月按部门统计每类考勤次数」本质是行转列付表二是「某月员工各类考勤罚金小计和总计」是带合计行的分组聚合。-- 付表一按月按部门统计每类考勤次数行转列 SELECT d.depName AS 部门, SUM(CASE WHEN c.check_name 事假 THEN 1 ELSE 0 END) AS 事假, SUM(CASE WHEN c.check_name 病假 THEN 1 ELSE 0 END) AS 病假, SUM(CASE WHEN c.check_name 迟到 THEN 1 ELSE 0 END) AS 迟到, SUM(CASE WHEN c.check_name 缺席 THEN 1 ELSE 0 END) AS 缺席, SUM(CASE WHEN c.check_name 早退 THEN 1 ELSE 0 END) AS 早退 FROM emp_work_check_info c JOIN emp_info e ON c.emp_no e.emp_no JOIN dep_info d ON e.dep_no d.dep_no WHERE DATE_FORMAT(c.check_date, %Y-%m) :month -- 如 2024-06 GROUP BY d.dep_no, d.depName ORDER BY d.dep_no;这段的关键在CASE WHEN做行转列。考勤类型是存在work_check_categories表里的理论上可以动态生成列但报表列固定时硬编码更直观、性能也更好。DATE_FORMAT会把check_date上的索引废掉如果数据量大改成check_date :monthStart AND check_date :nextMonthStart的范围查询能走索引。-- 付表二某月员工各类考勤罚金小计与总计 SELECT e.empName AS 员工, SUM(CASE WHEN c.check_name 事假 THEN c.fine ELSE 0 END) AS 事假, SUM(CASE WHEN c.check_name 病假 THEN c.fine ELSE 0 END) AS 病假, SUM(CASE WHEN c.check_name 迟到 THEN c.fine ELSE 0 END) AS 迟到, SUM(c.fine) AS 合计 FROM emp_work_check_info c JOIN emp_info e ON c.emp_no e.emp_no WHERE DATE_FORMAT(c.check_date, %Y-%m) :month GROUP BY e.emp_no, e.empName WITH ROLLUP; -- 自动生成总计行WITH ROLLUP会在结果末尾追加一行总计省去在应用层再算一次。注意它生成的合计行里员工字段是NULL前端渲染时要判断一下别直接显示成空白。罚金小计依赖emp_work_check_info.fine字段如果罚金规则会变更规范的做法是统计时用work_check_categories.fine关联计算而不是存冗余的罚金值这一点文档里没展开但实际维护时差别很大。4. 避坑与排查这份设计里最容易翻车的五个点4.1 表名和字段名拼写错误现象建完表写查询book_info和emp_info混着用接口报「表不存在」。原因文档里员工表叫book_info明显是从图书管理模板改过来的遗留。解决统一改成emp_info字段phote改成photo在团队里定一次命名规范后面所有代码和文档跟着走。4.2 考勤信息表主键定义矛盾现象同一天同一员工插入两条迟到记录统计时次数翻倍。原因文档一处说主键是bh摘要说主键是「员工编号 考勤日期」两处冲突照抄容易漏掉唯一约束。解决用自增或业务编号做单主键额外对(emp_no, check_date, check_name)建唯一索引从数据库层挡住重复。4.3 罚金字段精度不够现象某次罚款 1200 元存进NUMERIC(3)直接报溢出或截断成 999。原因NUMERIC(3)总位数只有 3 位。解决改成NUMERIC(8,2)保留两位小数上限到百万级够中小型企业用。4.4 密码字段又短又明文现象用户表user_pwd VARCHAR(10)存哈希根本放不下有人干脆存明文。原因文档设计时没考虑加密。解决字段扩到VARCHAR(64)以上存 BCrypt 或 SHA-256 加盐后的值登录时比对哈希而不是明文。4.5 统计查询拖垮数据库现象月底跑付表一几万条考勤记录查了几十秒。原因DATE_FORMAT(check_date, %Y-%m)让check_date索引失效全表扫描。解决改成范围条件check_date 2024-06-01 AND check_date 2024-07-01并在check_date上建索引实测从十几秒降到毫秒级。5. 进阶把逻辑设计变成可维护的物理设计文档给的是逻辑结构真正上线前还得做几件事。第一是补索引除了主键和外键emp_info.empName、emp_work_check_info.check_date这两个高频查询字段都该单独建索引。第二是考虑分区考勤表是按时间增长的数据量大了可以按check_date做范围分区历史数据归档时直接DROP PARTITION比DELETE快得多。第三是加审计字段create_time、update_time、operator这三个字段文档里没有但出了数据问题要追责时没有它们就是黑匣子。验证设计是否合理我一般用两个动作。一是拿付表一和付表二的 SQL 各跑一遍看结果能不能对上手工算的样例数据二是往考勤表里插一批跨月、跨部门、含重复类型的测试数据检查唯一索引和统计口径有没有漏洞。这两步走完基本能挡住八成返工。还有个习惯每次拿到这类数据库设计文档我都会先把字段名和类型过一遍把明显是模板遗留的拼写、类型错误标出来再动手建表。血泪经验是前期改一个字段名花五分钟后期改可能要动十几处代码和几万条数据。希望这份拆解帮到你拿到文档后能直接落库、直接跑统计少走我踩过的弯路。本文还有配套的精品资源点击获取
网站建设高端定制企业官网