MySql:多表设计---外键

本文通过一个部门与员工的实例,详细介绍了如何使用外键约束来维护数据库中多表间的一致性和完整性,避免数据异常。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在实际开发过程中,一张表显然是不能满足我们的需求,通常我们需要多张表来存储数据。那么下面就举个栗子~
一家公司有多个部门,而每个部门有多个员工,现在我们来新建一个部门表:dept   以及一个员工表:emp。
建表的操作这里不再演示,如有需要请参考:
《MySql:操作表的语句以及常用的字段类型》 http://blog.youkuaiyun.com/javy_codercoder/article/details/49099271
以下为dept表的结构:
+-------+-------------+------+-----+---------+----------------+
| Field | Type             | Null | Key | Default | Extra                  |
+-------+-------------+------+-----+---------+----------------+
| id      | int(11)         | NO   | PRI  | NULL    | auto_increment |
| name| varchar(20) | NO   |        | NULL     |                            |
+-------+-------------+------+-----+---------+----------------+
以下为emp表的结构:
+--------+-------------+------+-----+---------+----------------+
| Field  | Type           | Null | Key | Default | Extra                   |
+--------+-------------+------+-----+---------+----------------+
| id      | int(11)         | NO   | PRI | NULL    | auto_increment |
| dept  | varchar(20) | YES  |       | NULL    |                             |
| name | varchar(20) | YES  |      | NULL    |                             |
| salary | double       | YES  |       | NULL    |                             |
+--------+-------------+------+-----+---------+----------------+
接下来就插入数据,插入数据也不再多说,有需要的可以看:
《MySql:增删改查(CRUD)以及乱码编码解决(1)》 http://blog.youkuaiyun.com/javy_codercoder/article/details/49121459
以下为dept表的数据:
+----+--------+
| id | name   |
+----+--------+
|  1 | 人事部 |
|  2 | 后勤部 |
|  3 | 财务部 |
|  4 | 行政部 |
+----+--------+
假设有两位员工分别叫做:小明和小芳分别属于人事部 和后勤部。
有一天老板发现后勤部没什么用然后就把后勤部砍掉了,对于数据库来说就是dept表把id为2的这一行数据删掉。
到了发工资的日期,小芳来到财务部领工资,那么财务部的妹子在电脑上发现没有后勤部啊。这个时候小芳就蒙蔽了~~我人还在部门就没了~~~
显然这种多表设计是可行的,但是是不完善的,不严谨的。
为了能够无时无刻维持着两个表的关系,我们需要引入一种叫做外键约束的技术。
我们在创建表时候可以声明表和表之间的关系,命令数据库帮我们维持这种关系。
如果有外键约束的话就不会发生以上案例的事情。在表dept删除id为2的数据时候会发生错误,因为在emp表还有一个小芳对应着dept表中id为2的数据。
显然上面的emp表是要重新建表了,因为在开始建表的时候没有加入外键约束,
那么我们来看看emp表的正确建表语句是怎样的:
create table emp(
id int primary key auto_increment,
name varchar(20),
dept_id int,
salary double,
foreign key(dept_id  ) references dept (id)
);
新建的emp表:
+---------+-------------+------+-----+---------+----------------+
| Field   | Type        | Null | Key | Default | Extra          |
+---------+-------------+------+-----+---------+----------------+
| id      | int(11)     | NO   | PRI | NULL    | auto_increment |
| name    | varchar(20) | YES  |     | NULL    |                |
| dept_id | int(11)     | YES  | MUL | NULL    |                |
| salary  | double      | YES  |     | NULL    |                |
+---------+-------------+------+-----+---------+----------------+
接下来我们插入两条数据:
insert into emp values(null,'曹操',1,2000);
insert into emp values(null,'荀彧',2,2000);
现在表里面的数据是这样的:
+----+------+---------+--------+
| id | name | dept_id | salary |
+----+------+---------+--------+
|  1 | 曹操 |       1 |   2000 |
|  2 | 荀彧 |       2 |   2000 |
+----+------+---------+--------+
我们依旧要删除掉二号部门:
delete from dept where id=2;
然后就会发现抛出一下错误:
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constrai
nt fails (`mydb`.`emp`, CONSTRAINT `emp_ibfk_1` FOREIGN KEY (`dept_id`) REFERENC
ES `dept` (`id`))

显然不然我们删除。这就是外键约束,能够避免人还在部门就没了的事情,那么外键约束能否避免无中生有的事情发生呢?
也就是我们尝试插入一个隶属于5号部门的员工到emp表中,注意这个时候dept表只有四个部门而已。
我们试试:
insert into emp values(null,'郭嘉',5,2000);
会发现也会抛出错误:
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint f
ails (`mydb`.`emp`, CONSTRAINT `emp_ibfk_1` FOREIGN KEY (`dept_id`) REFERENCES `
dept` (`id`))

要删除2号部门必须要确保emp表没有属于2号部门的员工,要插入属于5号部门的员工必须确保dept表有5号部门。

多表设计:
要懂得多表设计就要先明白什么是多对一,多对多,一对一这三种关系。而且要清楚什么情况是多对一,多对多,一对一。
这里就不再叙述,可以百度一下~
多对一:
在多对一的情况下则在“多”的一方那个表参照”一“的那个表,也就是说在”多“的那个表设计一个外键关联”一“的那个表。
一对一:
而一对一的这种情况,是随意的~那个表参照哪个表都是没有所谓的。
多对多:
多对多这种情况就比较复杂,显然无论哪一方保存另一方的id都不合适,一个比较经典的案例就是老师和学生之间的关系,要保存哪个老师教过哪些学生怎么保存呢?一个学生可能被多个老师教过,而一个老师也不可能只教一个学生,那么对于这种情况怎么解决呢?
这个时候就需要新建多一张表出来,用于分别保存学生和老师的id作为外键:

id    stu_id   teach_id
1       1             6 
2       2             3
3       3             2
4       3             1
5       3             3
6       6             1

如上表所示,如果需要查询3号学生被哪些老师教过~那么就查stu_id=3的~就能查出1,2,3这三位老师都教过3号学生
如果想查1号老师教过哪些学生那么只需查teach_id=1的数据就能查出3,6学生被1号老师教过~




以下是基于需求分析的12个核心实体及关系设计: 1. Users (用户) -: user_id - 字段: username, password_hash, email, phone, register_time, last_login 2. Roles (角色) -: role_id - 字段: role_name, role_desc 3. User_Roles (用户角色关联) - 复合主: user_id, role_id - : user_id -> Users, role_id -> Roles 4. Books (图书信息) -: book_id - 字段: isbn, title, abstract, publish_year, word_count 5. Authors (作者) -: author_id - 字段: author_name, nationality, biography 6. Book_Authors (图书作者关联) - 复合主: book_id, author_id - : book_id -> Books, author_id -> Authors 7. Publishers (出版社) -: publisher_id - 字段: publisher_name, address, phone, website 8. Categories (图书分类) -: category_id - 字段: category_name, parent_id, description 9. Book_Copies (馆藏副本) -: copy_id - 字段: book_id, copy_status, purchase_date, location - : book_id -> Books 10. Loans (借阅记录) -: loan_id - 字段: user_id, copy_id, loan_date, due_date, return_date, status - : user_id -> Users, copy_id -> Book_Copies 11. Reservations (预约) -: reservation_id - 字段: user_id, book_id, reservation_date, status, notify_date - : user_id -> Users, book_id -> Books 12. Fines (罚款记录) -: fine_id - 字段: loan_id, fine_amount, fine_reason, paid_status, create_time - : loan_id -> Loans (一对一关联) 关系说明 一对一关系: Loans↔ Fines(一条逾期借阅记录对应一条罚款记录) 一对关系: Publishers → Books(一个出版社出版本书) Categories → Books(一个分类包含本书) Books → Book_Copies(一本书有个物理副本) Users → Loans(一个用户有条借阅记录) 关系: Users ↔ Roles(通过`User_Roles`中间) Books ↔ Authors(通过`Book_Authors`中间) Users↔ Books(通过`Reservations`中间实现预约) 生成ldm pdm 图
最新发布
06-17
<think>我们正在处理用户关于如何根据实体关系设计生成逻辑数据模型(LDM)和物理数据模型(PDM)图的问题。根据引用内容,我们可以知道:-概念数据模型(CDM)是独立于任何具体数据库平台的,它描述了数据的高层结构和关系。-逻辑数据模型(LDM)是在概念模型的基础上进一步细化,通常针对特定的业务规则,但仍然不依赖于具体的数据库管理系统(DBMS)。-物理数据模型(PDM)则是在逻辑模型的基础上,根据特定的数据库管理系统(如MySQL,Oracle等)进行具体实现的设计,包括结构、索引、约束等。用户希望从实体关系设计(通常对应于概念模型)生成LDM和PDM图。这里我们假设用户已经有一个概念模型(CDM),现在需要转换为LDM和PDM。根据引用[5]提到的工具PowerDesigner,我们可以使用它来完成从CDM到LDM再到PDM的转换过程。下面将详细说明步骤。###步骤1:从概念模型(CDM)生成逻辑模型(LDM)1.**打开概念模型**:在PowerDesigner中打开已有的CDM文件(.cdm)。2.**检查模型**:确保CDM中的实体、属性和关系已经正确定义。3.**生成逻辑模型**:-在菜单栏中选择“Tools”->“GenerateLogicalDataModel...”。-在弹出的对话框中,设置转换选项,例如:-选择是否在LDM中显示关联(Association)或使用(Reference)来示关系。-选择是否生成继承关系的具体化(将继承转换为结构)等。-点击“确定”生成LDM。4.**调整逻辑模型**:生成后,检查LDM是否符合业务规则。逻辑模型应该更详细,包括规范化处理(如满足第三范式)等。###步骤2:从逻辑模型(LDM)生成物理模型(PDM)1.**在逻辑模型基础上生成物理模型**:-在LDM文件中,选择“Tools”->“GeneratePhysicalDataModel...”。-选择目标数据库管理系统(例如MySQL、Oracle等)。-设置转换选项,例如:-是否生成、视图、存储过程等。-命名规则(例如名、列名的转换规则)。-数据类型映射(将逻辑模型中的数据类型映射到具体数据库的数据类型)。-点击“确定”生成PDM。2.**调整物理模型**:-检查生成的结构,包括主、索引等。-根据性能需求调整设计,例如添加索引、分区等。-可以修改具体的数据类型、长度、约束等。###步骤3:生成图形化示在PowerDesigner中,模型本身就以图形方式展示。你可以:-在每种模型(CDM,LDM,PDM)的图形视图中查看和调整布局。-通过菜单“Report”->“GenerateReport”生成模型文档。-导出为图片:在图形视图中,选择“File”->“ExportImage”将模型图导出为图片格式(如PNG,JPG等)。###注意事项-**数据类型的映射**:在生成PDM时,要特别注意逻辑模型中的数据类型到具体数据库数据类型的映射。例如,逻辑模型中的“字符串”在MySQL中可能是`VARCHAR`,而在Oracle中可能是`VARCHAR2`。-**命名规则**:确保在生成过程中命名规则一致,例如名和列名的转换(大小写、下划线分隔等)。-**约束和索引**:在PDM中,需要根据业务需求添加或调整约束(如唯一约束、非空约束)和索引。###其他工具除了PowerDesigner,还有其他工具可以完成类似转换,例如:-**ERWin**-**MySQLWorkbench**(可以直接设计逻辑模型和物理模型,但通常不经过CDM阶段)-**在线工具**(如dbdiagram.io,draw.io等)可以绘制,但自动转换功能有限。###总结生成逻辑数据模型(LDM)和物理数据模型(PDM)图的过程通常依赖于建模工具(如PowerDesigner)的转换功能。用户需要先有概念模型(CDM),然后通过工具逐步转换,并在转换过程中根据具体业务需求和目标数据库进行调整。§§相关问题§§1.概念数据模型(CDM)与逻辑数据模型(LDM)的主要区别是什么?2.在生成物理数据模型(PDM)时,如何优化数据库性能?3.PowerDesigner之,还有哪些工具可以用于数据建模?</think>### 如何根据实体关系设计生成逻辑数据模型(LDM)和物理数据模型(PDM)图 #### 一、核心步骤概述 1. **概念模型(CDM)→ 逻辑模型(LDM)** - **输入**:实体关系图(ERD),包含实体、属性、关系、约束 - **输出**:独立于具体数据库的规范化结构(满足第三范式) - **关操作**: -关系转换为关联实体 - 定义主/依赖关系 - 规范化属性(消除冗余)[^3][^4] 2. **逻辑模型(LDM)→ 物理模型(PDM)** - **输入**:已规范化的LDM - **输出**:针对具体数据库(如MySQL/Oracle)的实施方案 - **关操作**: - 映射数据类型(如`VARCHAR(255)` → `NVARCHAR(50)`) - 添加索引、分区、存储引擎配置 - 实现安全机制(用户权限、加密)[^2][^5] --- #### 二、详细操作指南(以PowerDesigner为例) ##### 步骤1:CDM → LDM 转换 1. **打开CDM文件** ```mermaid graph LR A[实体Student] -- 1:n --> B[实体Course] B -- m:n --> C[实体Teacher] ``` 2. **自动转换逻辑模型** - 菜单选择:`Tools` → `Generate Logical Data Model` -配置: - ✅ 自动转换关系为关联 - ✅ 生成约束命名规则(如`FK_Student_Course`) - ✅ 保留业务规则校验逻辑[^5] 3. **手动优化LDM** - 示例:将`Student`实体拆分为: ```mermaid erDiagram STUDENT ||--o{ ENROLLMENT : has ENROLLMENT }o--|| COURSE : for TEACHER ||--o{ COURSE : teaches ``` ##### 步骤2:LDM → PDM 转换 1. **选择目标数据库** - 菜单:`Tools` → `Generate Physical Data Model` - 选择数据库类型(如MySQL 8.0) 2. **配置物理参数** | 逻辑模型元素 | 物理模型实现 | |--------------------|--------------------------| | 属性 `StudentID` | `INT AUTO_INCREMENT PK` | | 关系 `1:n` | `ON DELETE CASCADE` | | 文本属性 `Name` | `VARCHAR(100) NOT NULL` | 3. **添加性能优化** - 在`ENROLLMENT`的`CourseID`字段创建索引: ```sql CREATE INDEX IDX_ENROLL_COURSE ON ENROLLMENT(CourseID); ``` - 配置存储引擎:`InnoDB`(支持事务) --- #### 三、关注意事项 1. **数据类型映射陷阱** - 逻辑模型中的`Text` → MySQL需明确`VARCHAR(255)`或`TEXT` - 浮点数精度:`DECIMAL(10,2)` vs `FLOAT`[^3] 2. **关系实现差异** - 继承关系:转换为单(所有属性合并)或(父+子- 弱实体:必须添加依赖(如`ORDER_ITEM`依赖`ORDER`) 3. **生成图形化输出** - PowerDesigner导出:`File` → `Export` → `PDF/PNG` - 自动生成SQL脚本:`Database` → `Generate Database` --- #### 四、工具替代方案 | 工具 | CDM→LDM | LDM→PDM | 图形输出 | |--------------------|---------|---------|---------| | **MySQL Workbench** | ❌ | ✅ | ✅ | | **ERwin** | ✅ | ✅ | ✅ | | **draw.io** | 手动 | 手动 | ✅ | > **提示**:简单项目可用[dbdiagram.io](https://dbdiagram.io)在线生成PDM(支持导出SQL/PNG)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值