当前位置: 首页 > news >正文

Mysql数据库多表设计

数据库表设计:一对一、一对多、多对多

在关系型数据库中,表与表之间的关系常见三种:一对一、一对多、多对多


1. 一对一(One-to-One)

概念

一条记录对应另一张表的唯一一条记录,常用于把“主表”和“扩展信息表”拆分存储。

示例:用户信息表 + 用户身份证表

-- 用户表
CREATE TABLE tb_user (id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT COMMENT 'ID',name VARCHAR(10) NOT NULL COMMENT '姓名',gender TINYINT UNSIGNED NOT NULL COMMENT '性别, 1 男  2 女',phone CHAR(11) COMMENT '手机号',degree VARCHAR(10) COMMENT '学历'
) COMMENT '用户信息表';-- 用户身份证表
CREATE TABLE tb_user_card (id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT COMMENT 'ID',nationality VARCHAR(10) NOT NULL COMMENT '民族',birthday DATE NOT NULL COMMENT '生日',idcard CHAR(18) NOT NULL COMMENT '身份证号',issued VARCHAR(20) NOT NULL COMMENT '签发机关',expire_begin DATE NOT NULL COMMENT '有效期限-开始',expire_end DATE COMMENT '有效期限-结束',user_id INT UNSIGNED NOT NULL UNIQUE COMMENT '用户ID',CONSTRAINT fk_user_id FOREIGN KEY (user_id) REFERENCES tb_user(id)
) COMMENT '用户身份证表';

在这里插入图片描述

设计要点:

  • tb_user 存储基本信息,tb_user_card 存储扩展信息。
  • tb_user_card.user_id 设置 UNIQUE 保证一对一关系。
  • 外键 FOREIGN KEY 保证数据一致性。

2. 一对多(One-to-Many)

概念

一张表的一条记录,对应另一张表的多条记录,最常见的关系(父子关系)。

示例:部门表 + 员工表

-- 部门表
CREATE TABLE tb_dept (id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT COMMENT '部门ID',name VARCHAR(10) NOT NULL UNIQUE COMMENT '部门名称',create_time DATETIME COMMENT '创建时间',update_time TIMESTAMP COMMENT '更新时间'
) COMMENT '部门表';-- 员工表
CREATE TABLE tb_emp (id INT PRIMARY KEY AUTO_INCREMENT COMMENT '员工id',username VARCHAR(20) NOT NULL UNIQUE COMMENT '用户名',name VARCHAR(10) NOT NULL COMMENT '姓名',gender TINYINT COMMENT '性别,1男 | 2女',dept_id INT UNSIGNED COMMENT '部门ID',entrydate DATE COMMENT '入职时间',CONSTRAINT fk_emp_dept FOREIGN KEY (dept_id) REFERENCES tb_dept(id)ON UPDATE CASCADEON DELETE SET NULL
) COMMENT '员工表';

在这里插入图片描述

设计要点:

  • tb_dept.id 是主表主键,tb_emp.dept_id 是外键。
  • 一个部门可以对应多名员工。
  • ON DELETE SET NULL 避免删除部门时导致员工记录丢失。

3. 多对多(Many-to-Many)

概念

一张表的一条记录可以对应另一张表的多条记录,反之亦然,需通过中间表实现。

示例:学生表 + 课程表 + 中间表

非常好的问题!
答案是:可以同时存在主键 id 和联合唯一索引,但不能同时存在两个主键。
我帮你详细拆解一下,让你彻底理解。


在多对多中间表中,有两种常见设计方式:


方案 1:联合主键(推荐,最简洁)

CREATE TABLE tb_student_course (student_id INT NOT NULL,course_id INT NOT NULL,PRIMARY KEY (student_id, course_id),  -- 联合主键CONSTRAINT fk_student FOREIGN KEY (student_id) REFERENCES tb_student(id),CONSTRAINT fk_course FOREIGN KEY (course_id) REFERENCES tb_course(id)
);

✅ 优点:

  • 主键天然保证 student_id + course_id 唯一。
  • 不需要额外字段,节省空间。
  • 查询性能好,直接走联合主键索引。

❌ 缺点:

  • 如果业务需要给这条“关系”单独添加扩展字段(比如选课时间、选课状态),插入、更新需要带上两个字段作为条件,不如单独 id 简洁。

方案 2:自增 id + 联合唯一索引(也常用)

CREATE TABLE tb_student_course (id INT PRIMARY KEY AUTO_INCREMENT,     -- 自增主键student_id INT NOT NULL,course_id INT NOT NULL,UNIQUE KEY uq_student_course (student_id, course_id), -- 联合唯一索引CONSTRAINT fk_student FOREIGN KEY (student_id) REFERENCES tb_student(id),CONSTRAINT fk_course FOREIGN KEY (course_id) REFERENCES tb_course(id)
);

✅ 优点:

  • id 作为单列主键,方便引用(比如其他表还要引用这条记录)。
  • 插入更新时可以用 id 操作,而不是带两个字段。
  • 适合中间表需要扩展更多业务字段(选课时间、成绩、状态等)。

❌ 缺点:

  • 多一个冗余字段,占用一点存储空间。
  • 需要额外创建联合唯一索引,才能防止重复数据。

能不能两个主键同时存在?

不能。
MySQL 规定一张表只能有一个主键,即使是联合主键,也是一个主键,只是由多个列组成。所以不能同时有:

id INT AUTO_INCREMENT PRIMARY KEY,  -- 单列主键
PRIMARY KEY (student_id, course_id) -- 联合主键

这样会报错:“Multiple primary key defined”。


推荐做法

场景推荐方案
纯粹的关联关系表,不需要额外字段方案 1:联合主键
需要扩展字段(选课时间、成绩、状态)或需要单独引用此记录方案 2:自增 id + 联合唯一索引

-- 学生表
CREATE TABLE tb_student (id INT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',name VARCHAR(10) COMMENT '姓名',no VARCHAR(10) COMMENT '学号'
) COMMENT '学生表';-- 课程表
CREATE TABLE tb_course (id INT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',name VARCHAR(10) COMMENT '课程名称'
) COMMENT '课程表';-- 学生课程中间表
CREATE TABLE tb_student_course (student_id INT NOT NULL COMMENT '学生ID',course_id INT NOT NULL COMMENT '课程ID',PRIMARY KEY (student_id, course_id), -- 联合主键,防止重复选课CONSTRAINT fk_courseid FOREIGN KEY (course_id) REFERENCES tb_course(id)ON DELETE CASCADE ON UPDATE CASCADE,CONSTRAINT fk_studentid FOREIGN KEY (student_id) REFERENCES tb_student(id)ON DELETE CASCADE ON UPDATE CASCADE
) COMMENT '学生课程中间表';

在这里插入图片描述

设计要点:

  • 中间表 tb_student_course 存两张主表的主键。
  • 可以加联合唯一索引 (student_id, course_id) 避免重复选课。
  • 通过 JOIN 查询多对多关系。

4. 三种关系对比

关系类型特点表设计关键点
一对一一条记录对应另一张表唯一一条记录外键 + UNIQUE
一对多一条记录对应另一张表多条记录外键 (多端表保存外键)
多对多两张表多对多互相关联需要中间表 + 两个外键

✅总结

  • 一对一 → 外键 + UNIQUE
  • 一对多 → 外键放在“多”的一端
  • 多对多 → 用中间表拆成两个一对多


文章转载自:

http://CY9wih4y.srndk.cn
http://yDI9dOQL.srndk.cn
http://RfILEwIO.srndk.cn
http://TCuuCS2x.srndk.cn
http://UWfTVXTC.srndk.cn
http://3Dvqx2P9.srndk.cn
http://aN1MTKC5.srndk.cn
http://MeSCDYcb.srndk.cn
http://vThfMZ5s.srndk.cn
http://Q9DjpF1B.srndk.cn
http://t3VtWi1w.srndk.cn
http://j9vUAYRq.srndk.cn
http://PTWIwMUr.srndk.cn
http://AHNdPQoU.srndk.cn
http://UB7HAQLX.srndk.cn
http://5WvL3wu8.srndk.cn
http://xivCqdYu.srndk.cn
http://Bc4bSRii.srndk.cn
http://IH5zalIc.srndk.cn
http://FHFckdvg.srndk.cn
http://XoD8AG8a.srndk.cn
http://Gs2m9Ajp.srndk.cn
http://BYqSf4t9.srndk.cn
http://mDkShY2W.srndk.cn
http://B4PoySML.srndk.cn
http://4Slv1IAm.srndk.cn
http://DPGFOzrT.srndk.cn
http://svq9JzA3.srndk.cn
http://MFRnVjmE.srndk.cn
http://zjZhcrON.srndk.cn
http://www.dtcms.com/a/380483.html

相关文章:

  • open和fopen的区别
  • 排序---选择排序(Selection Sort)
  • 玩转PostMan之调试天气接口-心知天气 API
  • OpenHarmony DHCP 全栈深度剖析:从 DhcpClientStateMachine 到双栈 dhcpd 的客户端-服务器架构设计与源码实现
  • Linux 前后台作业控制及管理
  • 【设计模式】题目小练2
  • 软考中级习题与解答——第五章_面向对象方法(2)
  • 【智慧城市】2025年中国地质大学(武汉)暑期实训优秀作品(4):智矿中国
  • wslg 应用白色边框问题(Jetbrains 系列白色边框)
  • jmeter配置数据库连接步骤
  • Dest1ny安全漫谈-如何做好一个安全项目
  • qt中给QListWidget添加上下文菜单(快捷菜单)
  • Elasticsearch的理解与使用
  • android ndk编译valgrind
  • 实现调用libchdb.a静态连接库中的未公开导出函数
  • Deepoc具身智能无人机:为天空装上「自主决策大脑」
  • JX2202 直阻变比智能测试系统:重构新能源电力检测效率标准
  • 2025 年PT展前瞻:人工智能+如何走进普通人的生活?
  • 【AI论文】分享即关爱:基于集体强化学习经验共享的高效语言模型(LM)后训练方法
  • 二、网页的“化妆师”:从零学习 CSS
  • Rustdesk server docker-compose 一键搭建教程
  • 江科大《STM32入门教程》
  • ABI解析智能合约
  • 数据分析入门——解读36页指标体系建设方案【附全文阅读】
  • 隐私保护的照片分享:基于 Secure JPEG 的解决方案
  • 【面试笔记-Java开发岗】
  • OpenLayers数据源集成 -- 章节八:天地图集成详解
  • “可信资产IPO +数链金融RWA” 链改2.0六方共识(深圳)
  • linux自定义网卡名字
  • 基于 OpenCV 的眼球识别算法以及青光眼算法识别