【MySQL】第七弹---深入理解数据库表约束:自增长、唯一键、外键及综合案例解析

devtools/2025/3/12 0:35:55/

个人主页: 熬夜学编程的小林

💗系列专栏: 【C语言详解】 【数据结构详解】【C++详解】【Linux系统编程】【MySQL】

目录

1 表的约束

1.1 自增长

1.2 唯一键

1.3 外键

1.4 综合案例 


1 表的约束

1.1 自增长


auto_increment:当对应的字段,不给值,会自动的被系统触发,系统会从当前字段中已经有的最大值+1操作得到一个新的不同的值通常和主键搭配使用,作为逻辑主键。
自增长的特点:

  • 任何一个字段要做自增长,前提是本身是一个索引(key一栏有值)
  • 自增长字段必须是整数
  • 一张表最多只能有一个自增长

案例:

创建表

# 自增的字段需要有索引,类型为整数,且只能有一个
mysql> create table t1 (id int primary key auto_increment,name varchar(10) not null );
Query OK, 0 rows affected (0.02 sec)mysql> desc t1;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(10) | NO   |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

插入数据

mysql> insert into t1 (name) values('张三'); # 只插入name,id默认从1开始
Query OK, 1 row affected (0.01 sec)mysql> select * from t1;
+----+--------+
| id | name   |
+----+--------+
|  1 | 张三   |
+----+--------+
1 row in set (0.00 sec)mysql> insert into t1 values(100,'张三'); # id插入指定的数,则插入指定的数
Query OK, 1 row affected (0.00 sec)mysql> select * from t1;
+-----+--------+
| id  | name   |
+-----+--------+
|   1 | 张三   |
| 100 | 张三   |
+-----+--------+
2 rows in set (0.00 sec)mysql> insert into t1 (name) values('李四'); # 再插入数值,不指定id,默认+1
Query OK, 1 row affected (0.00 sec)mysql> select * from t1;
+-----+--------+
| id  | name   |
+-----+--------+
|   1 | 张三   |
| 100 | 张三   |
| 101 | 李四   |
+-----+--------+
3 rows in set (0.00 sec)

mysql怎么知道我们插入前的数值是多少呢?

mysql> show create table t1 \G;
*************************** 1. row ***************************Table: t1
Create Table: CREATE TABLE `t1` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(10) NOT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=102 DEFAULT CHARSET=utf8 # AUTO_INCREMENT表示下次插入值的默认值
1 row in set (0.00 sec)

在插入后获取上次插入的 AUTO_INCREMENT 的值(批量插入获取的是第一个值)

mysql> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
|              101 |
+------------------+
1 row in set (0.00 sec)

索引:

        在关系数据库中,索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。索引的作用相当于图书的目录,可以根据目录中的页码快速找到所需的内容
        索引提供指向存储在表的指定列中的数据值的指针,然后根据您指定的排序顺序对这些指针排序。数据库使用索引以找到特定值,然后顺指针找到包含该值的行。这样可以使对应于表的SQL语句执行得更快,可快速访问数据库表中的特定信息

1.2 唯一键

一张表中有往往有很多字段需要唯一性,数据不能重复,但是一张表中只能有一个主键:唯一键就可以解决表中有多个字段需要唯一性约束的问题。

唯一键的本质和主键差不多,唯一键允许为空,而且可以多个为空,空字段不做唯一性比较

关于唯一键和主键的区别我们可以简单理解成,主键更多的是标识唯一性的。而唯一键更多的是保证在业务上,不要和别的信息出现重复。乍一听好像没啥区别,我们举一个例子

假设一个场景(当然,具体可能并不是这样,仅仅为了帮助大家理解)
比如在公司,我们需要一个员工管理系统,系统中有一个员工表,员工表中有两列信息,一个身份证号码,一个是员工工号,我们可以选择身份号码作为主键。
而我们设计员工工号的时候,需要一种约束:而所有的员工工号都不能重复。
具体指的是在公司的业务上不能重复,我们设计表的时候,需要这个约束,那么就可以将员工工号设计成为唯一键。
一般而言,我们建议将主键设计成为和当前业务无关的字段,这样,当业务调整的时候,我们可以尽量不会对主键做过大的调整。

案例:

创建表

# 给id 设置唯一键,也可以只写unique
mysql> create table t2(id char(10) unique key comment '学号,不能重复',-> name varchar(10) comment '姓名');
Query OK, 0 rows affected (0.02 sec)mysql> desc t2;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | char(10)    | YES  | UNI | NULL    |       |
| name  | varchar(10) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

插入数据

mysql> insert into t2 values(1,'张三');
Query OK, 1 row affected (0.01 sec)mysql> insert into t2 values(1,'李四'); # 插入id = 1的数据,因为唯一键的约束不能插入重复的数据
ERROR 1062 (23000): Duplicate entry '1' for key 'id'mysql> insert into t2 values(2,'李四');
Query OK, 1 row affected (0.00 sec)mysql> select * from t2;
+------+--------+
| id   | name   |
+------+--------+
| 1    | 张三   |
| 2    | 李四   |
+------+--------+
2 rows in set (0.00 sec)

1.3 外键

外键用于定义主表和从表之间的关系外键约束主要定义在从表上,主表则必须是有主键约束或unique约束。当定义外键后,要求外键列数据必须在主表的主键列存在或为null。

语法:

foreign key (字段名) references 主表(列)

没有使用外键(设计下面的结构)

创建表

mysql> create table class (id int primary key comment '班级号',name varchar(12) comment '班级名');
Query OK, 0 rows affected (0.04 sec)mysql> create table student(id int primary key comment '学号', name varchar(15) not null comment '姓名', telphone char(20) unique comment '电话号码', class_id int comment '班级号');
Query OK, 0 rows affected (0.06 sec)mysql> desc class;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   | PRI | NULL    |       |
| name  | varchar(12) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)mysql> desc student;
+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| id       | int(11)     | NO   | PRI | NULL    |       |
| name     | varchar(15) | NO   |     | NULL    |       |
| telphone | char(20)    | YES  | UNI | NULL    |       |
| class_id | int(11)     | YES  |     | NULL    |       |
+----------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

插入数据

class表

mysql> insert into class values(101,'通信1班');
Query OK, 1 row affected (0.01 sec)mysql> insert into class values(102,'通信2班');
Query OK, 1 row affected (0.00 sec)mysql> select * from class ;
+-----+------------+
| id  | name       |
+-----+------------+
| 101 | 通信1班    |
| 102 | 通信2班    |
+-----+------------+
2 rows in set (0.00 sec)

student表 

mysql> insert into student values(135792,'张三',123456,101);
Query OK, 1 row affected (0.01 sec)mysql> insert into student values(135795,'李四',654321,102);
Query OK, 1 row affected (0.01 sec)mysql> insert into student values(135786,'王五',654365,102);
Query OK, 1 row affected (0.00 sec)mysql> select * from student;
+--------+--------+----------+----------+
| id     | name   | telphone | class_id |
+--------+--------+----------+----------+
| 135786 | 王五   | 654365   |      101 |
| 135792 | 张三   | 123456   |      102 |
| 135795 | 李四   | 654321   |      102 |
+--------+--------+----------+----------+
3 rows in set (0.00 sec)

删除班级号等于 101 的class表数据

mysql> delete from class where id = 101;
Query OK, 1 row affected (0.00 sec)mysql> select * from class;
+-----+------------+
| id  | name       |
+-----+------------+
| 102 | 通信2班    |
+-----+------------+
1 row in set (0.00 sec)mysql> select * from student;
+--------+--------+----------+----------+
| id     | name   | telphone | class_id |
+--------+--------+----------+----------+
| 135786 | 王五   | 654365   |      102 |
| 135792 | 张三   | 123456   |      101 |
| 135795 | 李四   | 654321   |      102 |
+--------+--------+----------+----------+
3 rows in set (0.00 sec)

班级101还有学生,但是班级却没有了,这合理吗?按照现实来看,这是不合理的,因此我们应该怎么解决这个问题呢???

此处可以用到外键。

以 student 为从表,class 为主表建立外键关系。

  • 为了让约束能够正确设置,我们先删除主表的内容,删除从表,并重新创建从表。

删除数据及表结构

mysql> delete from class  where id = 102;
Query OK, 1 row affected (0.01 sec)mysql> drop table student;
Query OK, 0 rows affected (0.02 sec)mysql> select * from class;
Empty set (0.00 sec)

创建从表student

mysql> create table student(id int primary key,-> name varchar(15) not null,-> telphone char(20) unique,-> class_id int,-> foreign key(class_id) references class(id));
Query OK, 0 rows affected (0.09 sec)mysql> desc student;
+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| id       | int(11)     | NO   | PRI | NULL    |       |
| name     | varchar(15) | NO   |     | NULL    |       |
| telphone | char(20)    | YES  | UNI | NULL    |       |
| class_id | int(11)     | YES  | MUL | NULL    |       |
+----------+-------------+------+-----+---------+-------+
4 rows in set (0.01 sec)

插入数据

mysql> insert into class values(101,'通信1班');
Query OK, 1 row affected (0.01 sec)mysql> insert into class values(102,'通信2班');
Query OK, 1 row affected (0.00 sec)mysql> select * from class;
+-----+------------+
| id  | name       |
+-----+------------+
| 101 | 通信1班    |
| 102 | 通信2班    |
+-----+------------+
2 rows in set (0.00 sec)mysql> insert into student values(123,'张三',123456,101);
Query OK, 1 row affected (0.01 sec)mysql> insert into student values(124,'李四',654321,102);
Query OK, 1 row affected (0.01 sec)mysql> insert into student values(125,'王五',294321,102);
Query OK, 1 row affected (0.01 sec)mysql> select * from student;
+-----+--------+----------+----------+
| id  | name   | telphone | class_id |
+-----+--------+----------+----------+
| 123 | 张三   | 123456   |      101 |
| 124 | 李四   | 654321   |      102 |
| 125 | 王五   | 294321   |      102 |
+-----+--------+----------+----------+
3 rows in set (0.00 sec)

删除数据

mysql> delete from class where id = 101; # 删除主表内容,因为有外键约束,从表中有数据,因此不能删除
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test3_db`.`student`, CONSTRAINT `student_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `class` (`id`))mysql> delete from class where id = 102; # 同上,不能删除
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test3_db`.`student`, CONSTRAINT `student_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `class` (`id`))mysql> delete from student where class_id = 101; # 删除从表数据可以直接删除
Query OK, 1 row affected (0.00 sec)mysql> delete from student where class_id = 102;
Query OK, 2 rows affected (0.00 sec)mysql> select * from student; # 从表为空
Empty set (0.00 sec)mysql> delete from class where id = 101; # 从表为空可以直接删除主表内容
Query OK, 1 row affected (0.00 sec)

1.4 综合案例 


有一个商店的数据,记录客户及购物情况,有以下三个表组成:

  • 商品goods(商品编号goods_id,商品名goods_name, 单价unitprice, 商品类别category, 供应商provider)
  • 客户customer(客户号customer_id,姓名name,住址address,邮箱email,性别sex,身份证card_id)
  • 购买purchase(购买订单号order_id,客户号customer_id,商品号goods_id,购买数量nums)

要求:

  • 每个表的主外键
  • 客户的姓名不能为空值
  • 邮箱不能重复
  • 客户的性别(男,女)

商品表

mysql> create table if not exists goods (-> goods_id int primary key auto_increment comment '商品编号',-> goods_name varchar(32) not null comment '商品名称',-> unitprice float not null default 0.25 comment '商品单价',-> category varchar(12) comment '商品分类',-> provider varchar(40) not null comment '供应商');
Query OK, 0 rows affected (0.04 sec)mysql> desc goods;
+------------+-------------+------+-----+---------+----------------+
| Field      | Type        | Null | Key | Default | Extra          |
+------------+-------------+------+-----+---------+----------------+
| goods_id   | int(11)     | NO   | PRI | NULL    | auto_increment |
| goods_name | varchar(32) | NO   |     | NULL    |                |
| unitprice  | float       | NO   |     | 0.25    |                |
| category   | varchar(12) | YES  |     | NULL    |                |
| provider   | varchar(40) | NO   |     | NULL    |                |
+------------+-------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)

客户表

mysql> create table if not exists customer ( customer_id int primary key auto_increment comment '客户编号', name varchar(12) not null comment '客户姓名', address varchar(20) comment '客户地址', email varchar(64) unique key comment '电子邮箱', sex enum('男','女') not null comment '客户性别', card_id char(18) unique comment '身份证');
Query OK, 0 rows affected (0.03 sec)mysql> desc customer;
+-------------+-------------------+------+-----+---------+----------------+
| Field       | Type              | Null | Key | Default | Extra          |
+-------------+-------------------+------+-----+---------+----------------+
| customer_id | int(11)           | NO   | PRI | NULL    | auto_increment |
| name        | varchar(12)       | NO   |     | NULL    |                |
| address     | varchar(20)       | YES  |     | NULL    |                |
| email       | varchar(64)       | YES  | UNI | NULL    |                |
| sex         | enum('男','女')   | NO   |     | NULL    |                |
| card_id     | char(18)          | YES  | UNI | NULL    |                |
+-------------+-------------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)

购买表

mysql> create table if not exists purchase( order_id int primary key auto_increment comment '订单号',  customer_id int comment '客户编号', goods_id int comment '商品编号', num int default 0 comment '购买数量', foreign key(customer_id) references customer(customer_id), foreign key(goods_id) references goods(goods_id));
Query OK, 0 rows affected (0.03 sec)mysql> desc purchase;
+-------------+---------+------+-----+---------+----------------+
| Field       | Type    | Null | Key | Default | Extra          |
+-------------+---------+------+-----+---------+----------------+
| order_id    | int(11) | NO   | PRI | NULL    | auto_increment |
| customer_id | int(11) | YES  | MUL | NULL    |                |
| goods_id    | int(11) | YES  | MUL | NULL    |                |
| num         | int(11) | YES  |     | 0       |                |
+-------------+---------+------+-----+---------+----------------+
4 rows in set (0.00 sec)


http://www.ppmy.cn/devtools/166407.html

相关文章

【软考-架构】2.3、设备管理-文件管理

✨资料&文章更新✨ GitHub地址:https://github.com/tyronczt/system_architect 文章目录 设备管理概述🌟I/O软件设备管理技术💯考试真题文件管理概述✨索引文件结构💯考试真题文件目录💯考试真题文件存储空间管理位…

串口助手的C#编写以及有人串口服务器USR-DR301的使用

本文介绍C#编写串口程序的要点,串口服务器USR-DR301(RS232转TCP)的使用、以及调试过程中碰到的两个问题: 1). 调用串口报“连到系统上的设备没有发挥作用”. 2). “所有文本框都变成了透明”的异常处理 代码见:https://download.csdn.net/download/qq_34047402/9046713…

MySQL创建数据库和表,插入四大名著中的人物

一、登录数据库并创建数据库db_ck 二、创建表t_hero 表属性包括(id,name,nickname,age,gender,address,weapon,types) mysql> create table t_hero(-> id int,-…

动态 SQL 的使用

目录 1、< if> 标签2、< trim> 标签3、< where> 标签4、< set> 标签5、< foreach> 标签 1、< if> 标签 < if test“条件语句”> xxxx < /if> 只有当条件语句满足条件&#xff0c;才会拼接 < if> 标签内容&#xff0c;因…

拒绝“浅尝辄止”让考研知识深入人心

深入理解&#xff0c;而非浅尝辄止&#xff1a;考研知识的深度学习之路 在当今竞争激烈的学术环境中,考研已成为许多学生追求更高学历的重要途径&#xff0c;面对浩瀚的知识海洋和繁重的复习任务&#xff0c;不少考生往往陷入“浅尝辄止”的困境&#xff0c;未能真正深入理解和…

蓝桥杯省赛真题C++B组-裁纸刀2022

一、题目 问题描述 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 小蓝有一个裁纸刀&#xff0c;每次可以将一张纸沿一条直线裁成两半。 小蓝用一张纸打印出两行三列共 6 个二维码&#xff0c;至少使用九次裁出来&#x…

KafkaRocketMQ

Kafka 消息生产与消费流程 1. 消息生产 生产者创建消息&#xff1a; 指定目标 Topic、Key&#xff08;可选&#xff09;、Value。可附加 Header 信息&#xff08;如时间戳、自定义元数据&#xff09;。 选择分区&#xff08;Partition&#xff09;&#xff1a; 若指定 Key&am…

Java集合_八股场景题

Java集合 在Java开发中&#xff0c;集合框架是面试和实际开发中非常重要的内容。以下是一些常见的Java集合八股文问题和场景题&#xff0c;以及详细答案和示例代码。 1. Java集合框架的结构是什么&#xff1f; 答案&#xff1a; Java集合框架主要分为三大接口&#xff1a;Col…