ARTICLE DETAIL

资讯详情

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

人力资源管理系统ER图设计:从实体识别到MySQL建表避坑指南

人力资源管理系统ER图设计:从实体识别到MySQL建表避坑指南 简介本资源为人力资源管理系统数据库设计文档核心内容为一份完整的ER实体关系图适合数据库课程设计、系统开发前期建模及毕业设计参考。文档清晰展示职员、招聘信息、部门信息、工资信息、考勤信息等核心实体并给出招聘号、部门号、部门经理等关键属性及多对一、一对一关系的标注可直接辅助梳理表结构与业务逻辑。资源为单个doc文件压缩包约35KB轻量易用目前已有390人学习。对正在设计HRM数据模型或复习ER图绘制的学习者而言是一份能快速理解实体间关联、减少建模返工的实用参考资料。1. 人力资源管理系统er图.doc为什么建库之前要先画这张ER图一份名为“人力资源管理系统er图.doc”的文档往往是课程设计、毕业设计甚至小团队内部系统最早需要交付的产物。很多人拿到这个标题第一反应是打开Word画几个矩形和菱形交差但真正的问题不在“ER图怎么画”而在画之前你到底有没有把员工、部门、岗位、培训、考勤、薪资这些对象之间的关系想清楚。ER图画得越随意后面CREATE TABLE就越容易返工多对多不拆中间表、把部门当成属性塞进员工表这类问题几乎都是从这张图开始埋下的。这篇笔记按“语法—识实体—转表—避坑—迭代校验”的顺序把一张能真正指导建库的HRM ER图完整落地。适合刚学完《数据库系统概论》准备做系统设计的同学也适合要接手老HRM项目数据层、需要快速梳理模型的一线开发者。目标只有一个让你照着画完能直接写出不返工的表结构。2. 先把ER图语法立住实体、属性、联系在HRM里的落法与基数选择2.1 实体与属性把“员工”“部门”拆到什么粒度才不返工ER图三要素是实体矩形、属性椭圆、联系菱形这个语法本身不难难的是判断“一个对象算不算实体”。判断标准就三条它有没有独立的主键它有没有一串属于自己的属性业务系统要不要单独管理它的生命周期。拿人力资源管理场景试一下员工是实体因为要管工号、姓名、入职时间部门是实体因为部门有负责人、电话、编制数部门里的“员工姓名”就不是实体它只是员工实体的一个属性引用。很多新手把“部门名称”直接画在员工实体下面本质上就是把实体降级成了属性。属性的粒度同样影响落地。员工实体的常见属性集是工号、姓名、性别、出生日期、身份证号、联系电话、邮箱、住址、入职日期、在职状态。有一个老生常谈的坑不要在ER图里画“年龄”因为年龄是出生日期推导出来的派生属性存了就要不断维护查询时用TIMESTAMPDIFF计算更省事。另一个坑是“薪资”如果把它画成员工属性调薪就只能覆盖历史记录这个问题后面第4章展开讲。复合属性和多值属性也需要提前决定画法。员工的住址可以拆成省、市、区、详细地址四段这就是复合属性联系电话可能有手机、座机、紧急联系人电话这就是多值属性。ER图上多值属性用双线椭圆表达但关系模型里没有“多值字段”的合法位置所以落地时要么拆一张“员工联系电话表”要么在MySQL里用JSON字段。对HRM系统来说拆表更规矩JSON只适用于确实不查询、不参与关联的场景。注意实体识别有一条实用经验——先问“这个东西除了挂在员工身上之外有没有自己要管的属性”。部门有负责人所以是实体员工的学历只是履历的一部分所以先归为属性等出现“统计各学校人数”的需求时再升级成实体。2.2 联系的三种基数1对1、1对多、多对多分别落在哪些HR场景联系的基数决定了外键往哪放、要不要拆中间表。人力资源管理里三种基数都有典型场景而且相互之间的边界比教科书例题更容易画错。1对11:1员工和系统登录账号是典型。一个员工只有一个账号一个账号只属于一个员工。实现时外键放任意一边都行常见做法是账号表里放emp_id因为账号表依赖员工表存在。还有一种容易被忽略的1对1是“员工—工牌”如果系统要管工牌发放它就是一个独立的1对1联系。1对多1:N部门和员工是1:N一个部门有多个员工一个员工只属于一个部门。岗位和员工也是1:N一个岗位可以有多名员工。考勤更典型员工与考勤记录是1:N每个员工每天甚至每次打卡都是一条记录。这类联系在关系模型里实现最简单在“多”的一方加外键也就是在employee表里放dept_id、position_id。多对多M:N员工和培训课程是M:N一个员工可以参加多门课程一门课程有多个员工参加。员工和项目组在有些企业也是M:N一个员工参与多个项目一个项目由多人协作。M:N在关系模型里必须拆成中间表中间表里放两个外键再把联系自带的属性放进去。比如“参加培训”这个联系有成绩、完成状态、报名时间这些属性画在联系菱形上转表时落在emp_training中间表里。基数判断有个实用技巧先读句子。“一个部门有多少员工”——“多”的这端是员工“一个员工能参加多少门培训”——“多”的这端是培训课程。两句都成立就是M:N。只一句成立就是1:N。两句都不成立就是1:1。这个句读法比机械看箭头方向可靠得多。2.3 子类与弱实体什么时候该画ISA什么时候该合并子类ISA在HRM里最常见的讨论是员工分类正式工、实习生、外包人员。如果三类人员的属性差异很大比如正式工有合同编号、实习生有实习时长、外包有外包公司名称ER图上可以画出子类结构。但这个选择要付出代价转关系模型时要么把所有子类属性合并进一张大表大量NULL要么按子类拆表关联复杂。对一般规模的人力资源管理系统我建议用“员工类型”字段代替子类只是在ER图上注明“员工分为正式/实习/外包属性差异暂不单独建模”。这不是标准答案但它是事务型系统里性价比最高的做法。弱实体在HRM里也有对应对象员工家属。家属没有独立的业务标识必须依赖员工存在主键是“员工工号家属序号”的组合。如果系统需要维护直系亲属入职登记、紧急联系人就把它画成弱实体边框用双矩形。转表时家属表用复合主键第一个字段是emp_id第二个是seq。这个点在课程设计的ER图里是很好的加分项但注意不要滥用——只有生命周期完全从属于父实体的对象才配得上弱实体的身份。ER图的价值不在于把每个概念画得多么“标准”而在于让画图的人把业务规则逐条想清楚。子类与弱实体用得少不代表不用学恰恰是因为太多人不会用才导致实际系统里要么一堆NULL要么把家属硬做成独立实体。3. 从需求到ER图人力资源管理系统实体识别的三步走与主键设计3.1 第一步圈定系统边界列出候选实体拿到“人力资源管理系统”标题第一件事不是打开绘图工具而是先拆业务模块。常见模块有组织架构、员工档案、招聘、培训、考勤、薪资、系统用户。逐个模块过一遍把出现频率高的名词列出来这就是候选实体清单。我习惯用表格把模块和候选实体铺开再合并同类项模块候选实体是否必须组织架构部门、岗位必须员工档案员工、家属弱实体必须招聘招聘计划、应聘者、面试记录视范围定培训培训课程、培训报名中间表建议有考勤考勤记录、请假单必须薪资薪资单、薪资调整记录必须系统用户登录账号必须去重之后核心实体通常在8到10个左右。这里有一个容易纠结的点考勤记录的粒度。如果系统只用来看“某天某人有没有迟到”那考勤记录是“每人每天一条”如果要做门禁级审计那就变成“每次打卡一条流水”。粒度不同实体数量和ER图复杂度完全不同。我的建议是第一步先按“每人每天一条”设计等真出现秒级分析需求再拆流水表过度设计是ER图的第一个敌人。招聘模块要不要纳入取决于项目范围。如果是课程设计把招聘加进来能展示M:N联系和弱实体给ER图增加层次如果只是内部人事系统招聘可以先不进核心模型。边界一旦确定就写死在文档里避免画到一半不断加实体。3.2 第二步补齐属性与主键区分复合属性与多值属性确定实体后给每个实体列属性清单。以employee为例第一版属性表这样写字段名类型预估说明emp_idINT 自增代理主键系统内唯一emp_noCHAR(8)业务工号唯一约束nameVARCHAR(32)姓名genderCHAR(2)性别birth_dateDATE出生日期id_cardCHAR(18)身份证号唯一phoneVARCHAR(20)主电话emailVARCHAR(64)邮箱addressVARCHAR(128)住址复合属性摊平hire_dateDATE入职日期statusTINYINT0离职 1在职这一步会引出主键设计的关键决策用业务主键还是代理主键。业务主键是“工号”看起来方便但工号属于业务规则可能因为部门调整而变更一旦被引用为外键改动成本极高。代理主键是自增ID纯技术字段业务规则怎么变都不受影响。所以我建议employee表用自增INT做主键emp_no单独加UNIQUE约束。这个策略对部门、培训课程同样适用。属性表里还要标注哪些是复合属性、哪些是多值属性。address可以拆省市区但实际项目里通常直接用VARCHAR(128)存完整地址因为系统没有“按区统计员工”的需求。如果将来有再拆列也不迟这是摊平复合属性的务实选择。phone如果有多值存储需求新建employee_phone表每个员工多行主键是(emp_id, phone_seq)。不要在同一行里搞phone_1、phone_2、phone_3那会让自己写查询时怀疑人生。3.3 第三步连线并标注基数把ER图落到工具里属性整理完开始连线。核心联系就那么几条部门1:N员工、岗位1:N员工、员工1:N考勤、员工M:N培训课程、员工1:N薪资单、部门1:N岗位。先画这些主骨架再考虑登录账号1:1员工。连线的顺序建议从“最不容易变”的开始——先组织架构部门—岗位—员工再业务流转培训、考勤、薪资。工具选择只谈结论教材里常见用Rational Rose画ER图适合交作业但上手成本偏高Visio适合最终文档交付画出来规范Draw.io免费且导出图片方便适合快速草稿MySQL Workbench适合“先建表再反向出图”后面第6章细说。我的习惯是第一版用手在纸上画或者用文本列关系确定不改了再进工具精修避免在工具里反复挪框。第一版图完成后用一句话文字描述验证一下逻辑“部门与员工是1:N员工与培训课程通过报名信息形成M:N报名信息带成绩和完成状态员工与考勤是1:N考勤记录挂在员工下。”如果这句话读起来通顺再进工具画图。这一步能帮新手避免边画边改、图越画越乱的局面。4. 把ER图翻译成表结构CREATE TABLE映射过程与三个参数决策点4.1 实体转表的常规映射与主键策略ER图到关系模型的映射规则是固定的强实体转一张表属性转字段复合属性摊平多值属性拆表主键转主键。先看department和employee两张表的落地CREATE TABLE department ( dept_id INT AUTO_INCREMENT PRIMARY KEY COMMENT 部门ID代理主键, dept_no CHAR(4) NOT NULL UNIQUE COMMENT 部门编号业务唯一, dept_name VARCHAR(32) NOT NULL COMMENT 部门名称, manager_emp_id INT NULL COMMENT 部门负责人引用employee.emp_id环状引用先允许NULL, phone VARCHAR(20) COMMENT 部门电话, create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 建档时间 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT部门表; CREATE TABLE employee ( emp_id INT AUTO_INCREMENT PRIMARY KEY COMMENT 员工ID代理主键, emp_no CHAR(8) NOT NULL UNIQUE COMMENT 工号业务唯一约束, name VARCHAR(32) NOT NULL COMMENT 姓名, gender CHAR(2) COMMENT 性别, birth_date DATE COMMENT 出生日期, id_card CHAR(18) UNIQUE COMMENT 身份证号, phone VARCHAR(20) COMMENT 联系电话, email VARCHAR(64) COMMENT 邮箱, address VARCHAR(128) COMMENT 住址, dept_id INT NOT NULL COMMENT 所属部门外键, hire_date DATE COMMENT 入职日期, status TINYINT DEFAULT 1 COMMENT 0离职 1在职, CONSTRAINT fk_emp_dept FOREIGN KEY (dept_id) REFERENCES department(dept_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT员工表;逻辑说明department表里manager_emp_id指向employee表但employee表又有dept_id指向department表两个表形成环状引用。建表时必须先建department且manager_emp_id允许为空否则无法插入第一条数据。这是“先有鸡还是先有蛋”问题的经典解法入职后再由上层业务维护负责人字段。参数说明dept_no用CHAR(4)固定长度因为部门编号通常有固定编码规则id_card用CHAR(18)而不是VARCHAR身份证长度固定CHAR避免变长字段的存储开销gender用CHAR(2)而不是TINYINT直接存“男/女”查询时不用JOIN字典表status用TINYINT节省空间配合索引能快速过滤在职员工。4.2 多对多联系必须拆成中间表以员工—培训为例员工与培训课程是M:N直接把train_id塞进employee表会导致一个员工多条重复记录主键失效、数据冗余。正确做法是拆中间表同时把联系属性成绩、完成状态放进中间表CREATE TABLE training ( train_id SMALLINT AUTO_INCREMENT PRIMARY KEY COMMENT 课程ID, train_name VARCHAR(64) NOT NULL COMMENT 课程名称, train_date DATE COMMENT 开课日期, train_hours DECIMAL(4,1) COMMENT 培训时长单位小时支持0.5小时粒度 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT培训课程表; CREATE TABLE emp_training ( emp_id INT NOT NULL COMMENT 员工ID外键, train_id SMALLINT NOT NULL COMMENT 课程ID外键, score DECIMAL(5,2) COMMENT 成绩百分制保留两位小数, complete_status TINYINT DEFAULT 0 COMMENT 0未完成 1已完成, signup_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 报名时间, PRIMARY KEY (emp_id, train_id), CONSTRAINT fk_et_emp FOREIGN KEY (emp_id) REFERENCES employee(emp_id), CONSTRAINT fk_et_train FOREIGN KEY (train_id) REFERENCES training(train_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT员工培训报名表;逻辑说明emp_training不是业务实体而是一个关联实体它存在的唯一目的是把两个外键拼在一起顺带存放联系自带的属性。如果后面需求变成“一个人可以报名同一门课多次补考”这个中间表主键就要加上期次字段扩展为(emp_id, train_id, exam_times)说明设计有余量。参数说明train_hours用DECIMAL(4,1)因为培训可能是0.5小时为单位整数类型装不下score用DECIMAL(5,2)最多存999.99百分制够用complete_status用TINYINT配合索引统计“某课程通过率”时效率高主键用复合主键(emp_id, train_id)天然防止重复报名省掉一条SELECT校验语句。4.3 一对多与一对一的两种外键落法一对多关系在“多”的一方加外键这个原则全表通用。员工表里的dept_id就是部门1:N员工落下来的外键考勤表里的emp_id就是员工1:N考勤落下来的外键。一对一关系稍微特殊外键放哪边都可以原则是放在“从动方”——登录账号表依赖员工存在所以account表里放emp_id并加UNIQUE约束既保证一对一又保证不会出现一个员工两个账号。递归联系是另一个高频场景员工和上级也是员工这种自引用关系在employee表里加一列manager_id即可ALTER TABLE employee ADD COLUMN manager_id INT NULL COMMENT 上级员工ID自引用外键, ADD CONSTRAINT fk_emp_manager FOREIGN KEY (manager_id) REFERENCES employee(emp_id);manager_id指向本表主键这就是“员工—上级”1:N递归关系的落地。查询某个员工的所有下属时用自连接或递归CTE。要注意的是CEO没有上级manager_id必须允许NULL否则根节点插不进去。还有一个进阶映射思路值得写进表设计薪资流水不要直接挂在员工ID上而是挂在“员工—岗位”关系上。薪资调整本质是因岗位变动或调薪触发的如果salary_record只存emp_id和金额历史岗位信息丢失更好的设计是salary_record里存emp_id、position_id、生效日期、调整后金额这样能回答“张三做项目经理那年工资多少”。这是ER图转表时最容易忽略的“时间维度”提前考虑能省后面一大堆报表取数逻辑。5. 人力资源管理系统ER图避坑指南5个高频翻车点的现象、根因与修正5.1 坑1多对多不拆中间表员工表里塞多个培训记录现象员工张三参加3次培训employee表里出现三行“张三”主键emp_id没法再唯一删除一行会连其他字段一起丢。原因画ER图时把员工和培训课程的关系理解成1:N直接在employee表加train_id字段。解决回到ER图重新判断基数——一个员工可以参加多门课一门课也可以有多个员工这是标准的M:N必须拆emp_training中间表。如果数据已经录进去了先创建training表和emp_training表再用INSERT INTO emp_training SELECT DISTINCT emp_id, train_id FROM employee_backup把数据搬过去最后删除employee表里的冗余列。5.2 坑2递归联系“员工—上级”基数或方向画反现象查“张三的上级”返回多行或者manager_id指向了另一个部门的无关人员。原因画ER图时把“上级”理解成员工实体的一个普通属性没有意识到上级本身也是员工且一对多方向是从“上级”指向“下属”。解决明确基数——一个上级有多个下属所以是1:N递归联系方向是上级1到下属N。落地时employee表加manager_id自引用查询用自连接SELECT e.name AS 员工, m.name AS 上级 FROM employee e LEFT JOIN employee m ON e.manager_id m.emp_id;注意LEFT JOIN而不是INNER JOIN否则没有上级的最高管理者会被过滤掉。5.3 坑3把部门当员工属性部门表建不起来现象部门名称、部门电话、部门负责人全部写进employee表想统计各部门人数只能GROUP BY字符串部门一改名就要全表UPDATE。原因画ER图时没有做实体识别认为部门只是员工的一个标签。解决判断“部门除了挂靠员工外还有没有独立属性”——有负责人、有电话、有编制数这就是实体。回到ER图把department画成独立实体employee和department连1:N联系employee表只保留dept_id外键。已经踩坑的数据要先把DISTINCT部门信息导入department表再回填employee.dept_id。5.4 坑4薪资等级挂在员工上调薪记录全丢现象员工调薪后直接UPDATE员工表的salary字段发工资时想查“一季度前他拿多少”查不到薪资审计完全对不上。原因把薪资理解成员工的属性但薪资是随时间变化的“事实记录”不是稳定属性。解决ER图里把“薪资变动”画成独立实体salary_record员工与它是1:N联系salary_record记录调整前金额、调整后金额、生效日期、经手人。当前薪资用一条SQL从salary_record取最新生效记录或者建视图展示不要在employee表里存可变薪资字段。这属于ER图设计阶段就要想清楚的“时间维度”问题。5.5 坑5只导出图片不留模型文件改版重画现象PPT里放的是ER图截图数据库改了三版图还是旧的问设计稿在哪只有一张打不开的文档。原因把ER图当成“交付物”而不是“设计工具”画完导出图片就再也不维护。解决设计稿必须保留可编辑源文件。一个省力的办法是用MySQL Workbench反向工程——它支持从已有表结构中直接生成EER图步骤是Database菜单选Reverse Engineer选择连接和数据库工具自动读表结构、外键关系并作图。“mysql的表导出er关系图”这个需求在Workbench里是原生功能修改表结构后重新执行一次就能刷新模型。这样图和库永远同步不会出现“图是旧的”这种尴尬。6. 迭代与校验用文本化ER图改版再用MySQL反向导出对照6.1 把ER图写成文本改版不用重画图形化的ER图改起来费劲挪一个框要选中三条连线。我后来习惯先用结构化文本描述ER图确认业务规则稳定后再上图[department] 1----N [employee] [position] 1----N [employee] [employee] 1----N [attendance_record] [employee] M----N [training] via emp_training(score, complete_status) [employee] 1----N [salary_record] [account] 1----1 [employee]这种文本表达方式和流行的“mermaid er图”思路一致——图从文本生成文本放Git里可以看diff改版时只改一行字。团队协作时评审的人不用打开绘图软件就能看懂结构。6.2 用MySQL Workbench反向导出去校验设计稿永远赶不上代码变化所以我把反向校验当成最后一道关卡。在MySQL Workbench里执行Database菜单的Reverse Engineer选择目标库工具会自动读取所有表、外键、唯一约束并生成EER图。拿这张反向图跟原始ER图对比重点看三处多对多是否都出现了中间表外键方向对不对1对1是否两边都有唯一约束。比对完没问题ER图和数据库就算真正对齐了。6.3 给ER图配一页数据字典每次画完图我都要求自己顺手写一页数据字典哪怕只是一个表格实体名、主键、外键、关键字段、一句话说明。这个习惯让ER图不再是一张孤立的图而是能指导建表、评审、排障的完整文档。我现在拿到任何一份HRM需求第一件事不是打开画图工具而是先把实体清单列出来再连线。这个顺序帮我避开了无数返工希望帮到你。本文还有配套的精品资源点击获取
返回列表