ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

人力资源管理系统ER图解析:从实体关系到MySQL建表实践

人力资源管理系统ER图解析:从实体关系到MySQL建表实践 简介人力资源管理系统实体关系ER图文档面向数据库初学者、系统开发人员及课程设计学生帮助理解HR系统数据建模的关键环节。文档围绕核心业务梳理了职员、部门信息、招聘信息、工资信息等实体并解析“职员—考勤信息”“职位—工资信息”“部门经理—职员”等典型关系对1:n、n:1等映射基数作了清晰说明能辅助读者掌握从业务需求到数据库表结构的转换思路。考勤信息表的日期、上下班时间、职员编号招聘信息表中的招聘号、姓名、工作经历以及部门信息中的部门号、电话号码、部门经理、部门名称等字段均有讲解可直观看出实体间的主外键关联。资料包含1个doc格式文件压缩包仅35KB内容精炼便于查阅目前已有390人学习使用。通过该文档可快速获取HR系统各模块实体划分、主外键关系以及ER图绘制要点也能作为数据库设计说明书、课程设计报告或系统开发阶段表结构设计的参考模板。1. 人力资源管理系统ER图为什么一份doc比一堆Excel表更值得先读“人力资源管理系统ER图.doc”这个名字乍看像课设产物实际拆开之后会发现它是整条数据库设计链路上最值钱的一环。我先后处理过不少类似项目需求方手里是一摞Excel考勤表、几张部门人员名册后端却要在一周内把库表结构定下来。没有ER图的共识大家只能在会上各说各话。这张ER图把职员、考勤、工资、招聘、部门五个实体以及它们之间的基数关系画清楚了等于把“元数据地图”提前铺好。适合三类人做管理信息系统课设的学生、刚接手HR系统改造的开发以及需要给业务方出一份可视化表结构文档的产品或设计。你不需要会画图能读懂关系、能跟着建表就够了。2. 实体、属性与关系五张表的主键与外键落点拆解拿到这份doc最容易犯的错是直接奔着字段去建表把实体和属性混在一起看。实际上ER图的拆解顺序应该是先认实体再摘属性最后才看关系。文档里一共给了五个实体我拆成下面这张清单主键候选是我按数据库设计习惯补的判断文档本身并没有专门标注主键。实体属性按文档原文主键候选说明职员职员编号、姓名、性别、所在部门号、职位职员编号全局核心表其他表大多围绕它考勤信息表日期、上班时间、职员编号、下班时间职员编号 日期文档没给考勤单号联合主键更稳工资信息表职位、在岗人数、工资数职位文档把工资挂在职位上说明按职位定薪招聘信息表招聘号、姓名、工作经历、所在部门号招聘号招聘号是业务单号不是职员编号部门信息部门号、部门名称、电话号码、部门经理部门号部门经理是部门属性同时引用职员主键2.1 五个核心实体的属性清单与主键选择属性清单看起来简单但主键选择里藏着三个容易被忽略的点。第一考勤信息表没有给出考勤编号属性只有日期、上班时间、职员编号、下班时间用“职员编号 日期”做联合主键是最稳的组合可以在数据库层面挡住同一个人同一天插入两条重复考勤。如果业务允许一天多次打卡那就再加一个自增序列做考勤明细id而不是跟联合主键较劲硬拆日期字段。第二工资信息表的主键要跟定薪方式走。文档明确写着工资信息表包含职位、在岗人数、工资数并且和职位之间画的是n1n1关系这基本就是在说“工资定级挂在职位上不挂在人上”。所以这张表的主键可以直接用职位字段。如果企业实际按个人定薪主键就要换成职员编号这个切换点我会在第3章专门给改法。第三招聘信息表里的招聘号是典型的业务单号它只代表“某一次招聘活动”不代表“某一个职员”。一次招聘可能面进来三个人也可能一个人没录上。招聘号的这个特性决定了它不能直接当职员表主键这个坑很多人要踩一次才能记住。2.2 关系基数怎么读n1n1、nn1、1n1 的含义与转换规则读这份doc最容易卡住的是那一串n1n1、nn1、1n1的标注。这不是标准ER图画法更像是手绘时为了省事写出来的紧凑写法最初看到确实有点玄学。我的读法是把每两个字符拆成一组看n1表示“多对一”1n表示“一对多”然后统一翻译成标准ER图的1:N或者N:1。文档里用这个紧凑写法记录了三组关键关系职员与考勤是1:n职位与工资是1:n部门经理与职员是1:1。最容易误解的是招聘信息与职员之间的“nn1”。只看缩写会以为招聘信息和职员是多对多实际语义是一次招聘可能收到多个应聘者最终录用其中一人成为职员所以从招聘到职员依旧是1:n。区分关键就一句话招聘是过程数据职员是状态数据。把这两个生命周期想明白就不会建出一张不必要的中间关联表。把ER图转成关系模式有一条固定规则一对多关系把“一”方的主键放到“多”方做外键多对多关系用中间表拆成两个一对多。按这条规则过一遍本图部门对职员是1:n外键落在“职员.所在部门号”职员对考勤是1:n外键落在“考勤.职员编号”职位对工资记录是1:n外键落在工资信息表的职位字段。部门经理比较特殊它是部门实体的属性引用的却是职员表主键属于1:1性质的外键引用不单独建表。提示如果用PowerDesigner或MySQL Workbench做逆向建模记得把文档里的n1n1这类标注手工改成标准1:N否则工具自动生成的脚本会带上奇怪的关系名后面维护文档时别人看不懂。3. 从ER图到MySQL建表用SQL把概念模型翻译成物理模型ER图画得再漂亮最终都要落到建表SQL上。这里最影响成败的是建表顺序先建被引用的表再建引用它的表。五张表里部门表最独立可以先建职员表引用部门表排第二考勤表引用职员表招聘表引用部门表排第三但部门表里的部门经理字段要引用职员表所以部门表的主体可以先建这个外键必须等职员表建完再补上。把顺序想清楚照抄下面SQL才不报错。3.1 建表语句先部门后职员外键跟着一对多走CREATE TABLE department ( dept_id VARCHAR(10) PRIMARY KEY COMMENT 部门号, dept_name VARCHAR(50) NOT NULL COMMENT 部门名称, phone VARCHAR(20) COMMENT 电话号码, manager_emp_id VARCHAR(10) NULL COMMENT 部门经理指向employee.emp_id后补外键 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT部门信息; CREATE TABLE employee ( emp_id VARCHAR(10) PRIMARY KEY COMMENT 职员编号, emp_name VARCHAR(50) NOT NULL COMMENT 姓名, gender CHAR(1) COMMENT 性别, position VARCHAR(50) COMMENT 职位, dept_id VARCHAR(10) COMMENT 所在部门号, manager_emp_id VARCHAR(10) NULL COMMENT 上级职员编号自关联, hire_recruit_id VARCHAR(20) NULL COMMENT 录用来源招聘号可空, CONSTRAINT fk_emp_dept FOREIGN KEY (dept_id) REFERENCES department(dept_id), CONSTRAINT fk_emp_manager FOREIGN KEY (manager_emp_id) REFERENCES employee(emp_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT职员信息; CREATE TABLE attendance ( emp_id VARCHAR(10) NOT NULL COMMENT 职员编号, att_date DATE NOT NULL COMMENT 日期, on_time TIME COMMENT 上班时间, off_time TIME COMMENT 下班时间, PRIMARY KEY (emp_id, att_date), CONSTRAINT fk_att_emp FOREIGN KEY (emp_id) REFERENCES employee(emp_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT考勤信息表; CREATE TABLE salary ( position VARCHAR(50) PRIMARY KEY COMMENT 职位, headcount INT COMMENT 在岗人数冗余统计建议用视图替代, salary_amount DECIMAL(10,2) COMMENT 工资数 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT工资信息表; CREATE TABLE recruitment ( recruit_id VARCHAR(20) PRIMARY KEY COMMENT 招聘号, cand_name VARCHAR(50) NOT NULL COMMENT 姓名, work_exp TEXT COMMENT 工作经历, dept_id VARCHAR(10) COMMENT 所在部门号, CONSTRAINT fk_rec_dept FOREIGN KEY (dept_id) REFERENCES department(dept_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT招聘信息表;字段类型上我选VARCHAR(10)而不是INT做主键是因为企业里的职员编号、部门号几乎都带前缀比如D001、E1024如果你们公司内部用的是纯数字ID改成BIGINT也可以但要注意外键两侧类型必须一致否则MySQL直接报外键错误。工资列用DECIMAL(10,2)而不是FLOAT金额精度问题用血泪教训证明过任何浮点类型做金额都是给自己埋雷。补部门经理外键的SQL要单独放因为它引用的是employee表建表顺序上必须后执行ALTER TABLE department ADD CONSTRAINT fk_dept_manager FOREIGN KEY (manager_emp_id) REFERENCES employee(emp_id);这段ALTER的作用是把“部门经理”从普通字段升级为受约束的外键。加完之后数据库会强制要求部门经理这一列的值必须是职员表里真实存在的emp_id不能填一个凭空捏造的编号。这里还有一个设计争议点salary表里的在岗人数。文档把在岗人数画进工资信息表我建表时保留了它但严格来说这是统计字段每次入职离职都要UPDATE一遍很容易漏。更省心的做法是建一个视图实时算CREATE VIEW v_dept_position_count AS SELECT dept_id, position, COUNT(*) AS headcount FROM employee GROUP BY dept_id, position;这样salary表里的headcount可以留着当历史快照也可以干脆删掉列只保留视图。要历史数据就留物化结果要实时准确就用视图二选一别两个都想要又不同步。3.2 样板查询验证关系是否建反的两条SQL表建完之后我习惯马上跑两条查询验证关系有没有建反。第一条验证“职位—工资”的1:n关系是否成立SELECT d.dept_id, d.dept_name, AVG(s.salary_amount) AS avg_salary FROM department d JOIN employee e ON d.dept_id e.dept_id JOIN salary s ON e.position s.position GROUP BY d.dept_id, d.dept_name;这条SQL里员工通过position字段关联到salary表走的就是文档里“职位1:n工资”那条关系。如果工资表主键不是position而是emp_id这里的JOIN条件就要改成e.emp_id s.emp_id。跑出来如果某个部门平均工资为空先查是不是有员工的position在salary表里找不到对应职位这是最典型的脏数据来源。第二条验证“职员1:n考勤”是否建对SELECT a.emp_id, e.emp_name, a.att_date, a.on_time FROM attendance a JOIN employee e ON a.emp_id e.emp_id WHERE a.on_time 09:00:00 AND a.att_date CURDATE() - INTERVAL 7 DAY ORDER BY a.att_date DESC;这条查询能跑通的前提是attendance表的外键和联合主键都建成功了。如果结果里出现同一个emp_id同一天两行不用怀疑业务先检查联合主键是不是没建上。另外外键建失败时MySQL常见报错是“Cannot add foreign key constraint”排查顺序固定三条两张表的字段类型是否完全一致、被引用字段是否有唯一索引、两张表字符集是否都是utf8mb4。ER图转物理模型时一半外键报错都是这几个原因。如果业务是按个人定薪而不是按职位定薪salary表要改成另外一套结构salary_id自增主键emp_id作为外键salary_amount存个人工资数。ER图上原本的“职位—工资”关系就变成“职员—工资”这是拿到文档后第一个要跟业务方确认的口径确认晚了后面返工成本很高。4. ER图避坑排查四个常见设计坑与改法ER图画出来的是一张理想关系网落库时真正的问题是“文档没写清楚的地方怎么办”。我从这张doc里挑了四个最容易翻车的点每条都按“现象 → 原因 → 解决”来拆这些坑基本覆盖了同类管理系统中80%的设计错误。4.1 “领导”关系不要为了一个角色单独建表现象总ER图右下方有个孤零零的“领导”联系。我见过有人照着它建了一张leader中间表字段就两个manager_id、emp_id一行代表一个下属关系。结果一个50人的部门产生了49行领导记录经理离职要删一片想查“这位经理管多少人”还得数行数。原因领导和被领导本质是职员实体内部的自关联不是独立实体。文档把“领导”单独画出来只是业务语义上要强调部门经理的管理者角色不代表需要新增实体表。把一对多关系硬展开成一张一行一行的独立表查询和删改都非常别扭。解决直接在employee表加manager_emp_id字段通过自关联外键约束它只能指向真实存在的职员ALTER TABLE employee ADD COLUMN manager_emp_id VARCHAR(10) NULL; ALTER TABLE employee ADD CONSTRAINT fk_emp_manager FOREIGN KEY (manager_emp_id) REFERENCES employee(emp_id);这里要注意区分两个“经理”字段department.manager_emp_id代表该部门对外公布的经理employee.manager_emp_id代表上下级汇报关系两者功能不同可以并存。普通职员的manager_emp_id留空即可不要为了省事填一个不存在的上级编号。4.2 “领取”关系基数标反会造出重复工资记录现象工资信息表下方写着“记录领取”有同事把它理解成职员工资之间的多对多关联建了一张pay_record中间表字段是emp_id、salary_id、pay_date。结果同一个月同一员工插入了两条工资记录财务对账怎么都对不上。原因“领取”是一个动作不是实体。文档里工资信息表的属性是职位、在岗人数、工资数配合“n1n1”已经说得很清楚工资定级挂在职位上。动作要记录的是“某个人某个月领了多少钱”应该作为流水处理而不是在职位工资和职员之间再挂一层多对多。解决如果业务需要留存每次发薪流水单独建一张发薪表用唯一键兜底CREATE TABLE salary_payment ( payment_id INT PRIMARY KEY AUTO_INCREMENT, emp_id VARCHAR(10) NOT NULL, pay_month CHAR(7) NOT NULL, amount DECIMAL(10,2) NOT NULL, UNIQUE KEY uk_emp_month (emp_id, pay_month) );唯一键uk_emp_month的意义是同一个员工同一个发薪月份只能有一条流水。这是让数据库兜底而不是靠应用层先SELECT再判断有没有重复应用层判断在高并发和多人同时操作时一定有漏网之鱼。4.3 招聘号招聘主键不能直接当职员主键用现象招聘信息表的主键是招聘号有经验不足的同学把招聘号直接复制到职员表做主键结果一次招聘同时录用两个人时第二条和第一条主键冲突怎么也插不进去。更隐蔽的做法是把招聘表直接加录用状态做成宽表一个招聘对应多个人时又拆出recruit2_name这类字段越改越乱。原因招聘号和职员编号是生命周期完全不同的两套编号。招聘号记录的是招聘活动的过程数据从发布到录用结束就闭环了职员编号伴随员工整个在职周期。ER图里画“招聘号是连接招聘信息和职员的纽带”指的是来源追溯不是主键共用。解决职员表主键仍然用emp_id另加一个可空的hire_recruit_id记录录用来源。如果一次招聘最多录用一人就给hire_recruit_id建UNIQUE约束如果允许一次招多人就只建普通索引不建唯一约束。注意不要把这两个字段之间建强制外键因为招聘信息归档后可能被清理而职员档案要一直保留外键会把两段生命周期强行绑死。4.4 部门经理冗余字段与同步更新的取舍现象部门表里存了department.manager_emp_id同时经理本人又是职员表里的一行。业务上做一次组织架构调整两条记录没有同步于是出现A部门经理的档案挂在B部门下面的数据事故查谁是这个部门的老大时答案都是错的。原因部门经理是典型的冗余设计——它是部门的一个属性同时又对应职员表的一行。ER图上的“部门经理与职员1n1”只描述了关系没有规定谁同步谁。落库后任何一条记录被独立更新都会造成不一致。解决把职员表作为权威来源更新组织架构时在同一个事务里完成两步START TRANSACTION; UPDATE employee SET dept_id D002 WHERE emp_id E1001; UPDATE department SET manager_emp_id E1001 WHERE dept_id D002; COMMIT;事务里先改职员表再改部门表顺序不能颠倒。如果团队里有人习惯直接改库不走应用再加一个触发器兜底AFTER UPDATE ON employee的触发器检测到dept_id变化时自动刷新department.manager_emp_id。触发器的缺点是逻辑藏在库里不好排查所以我的习惯是应用层事务为主触发器只当最后一道防线。5. 进阶复绘ER图并用逆向工程核对关系设计5.1 用draw.io把局部ER图复绘一遍拿到这份doc我建议第一步别急着建表先在draw.io里把局部ER图复绘一遍做实体对齐。不需要纠结ER图怎么画这种问题照文档抄就行把部门信息、职员、考勤信息表、工资信息表、招聘信息表逐个画成实体框属性按文档原文放进去再按总ER图连线。复绘的过程会逼你把每个字段放到对应位置画完基本能发现文档里没写清楚的边界比如考勤表的主键到底怎么定、工资表挂在职位还是挂在人上这些问题在复绘时就会暴露出来。5.2 用information_schema核对外键清单如果已经按前面章节建好了表最快验证关系设计的方式是让工具从MySQL导出ER关系图或者直接查information_schema把外键清单拉出来逐条核对SELECT table_name, column_name, referenced_table_name, referenced_column_name FROM information_schema.key_column_usage WHERE table_schema DATABASE() AND table_name IN (employee, attendance, salary, recruitment, department);我希望看到的结果应该严格对应文档里的关系employee.dept_id指向department.dept_idattendance.emp_id指向employee.emp_idrecruitment.dept_id指向department.dept_iddepartment.manager_emp_id指向employee.emp_id。salary表没有外键是正常现象因为它按职位定级。我以前吃过一次亏拿到一张ER图没复绘就直接建表结果外键漏了两条接口联调时查不到跨部门数据才回头补。从那以后我每次拿到这类ER图doc都强制走一遍“复绘 → 拉外键清单 → 对关系”的流程宁可多花半小时也不让表结构留下后悔药。希望帮到你。本文还有配套的精品资源点击获取
返回列表