这篇文章只是对以前的内容作个详细补充,想要速成操作的,可以参考这篇博客 【MySQL学习】:关系数据库标准语言SQL
在进行具体表操作之前,我们需要先选定具体的数据库
mysql> use learn1;
Database changed
如果我们不记得我们选的是哪个数据库了,也可以进行查看,如下:
select database();
语法:
CREATE TABLE table_name (
field1 datatype,
field2 datatype,
field3 datatype
) character set 字符集 collate 校验规则 engine 存储引擎;
📚 说明:
field
: 表示列名datatype
: 表示列的类型character set
: 字符集,如果没有指定字符集,则以所在数据库的字符集为准collate
: 校验规则,如果没有指定校验规则,则以所在数据库的校验规则为准desc 表名;
在项目实际开发中,经常修改某个表的结构,比如字段名字,字段大小,字段类型,表的字符集类型,表的存储引擎等等。
我们还有需求,添加字段,删除字段。这时我们就需要修改表。 不会存在查找 !
ALTER TABLE tablename ADD (column datatype [DEFAULT expr][,column datatype]...);
ALTER TABLE tablename MODIfy (column datatype [DEFAULT expr][,column datatype]...);
ALTER TABLE tablename DROP (column);
drop table t1;
说明:
① 创建表
create table if not exists user1(
id int,
name varchar(20) comment '用户名',
password varchar(20) comment '用户密码',
birthday date comment '用户生日'
)character set utf8 collate utf8_general_ci engine MyIsam;
# 两种存储引擎,可以用 空格 或者 = 来设置
create table if not exists user2(
id int,
name varchar(20) comment '用户名',
password varchar(20) comment '用户密码',
birthday date comment '用户生日'
)character set utf8 collate utf8_general_ci engine=InnoDB;
if not exists
表示不存在再创建说明:
不同的 存储引擎 ,创建表的文件不一样。
MyISAM
,在数据目中有三个不同的文件,分别是:users.frm
:表结构users.MYD
:表数据users.MYI
:表索引而当存储引擎是 InnoDB
,在数据目中有两个不同的文件
Users.frm
:表结构Users.ibd
:表数据&表索引② 插入| 删除 | 查看 表数据
③ 查看表信息
④ 修改表信息
Ⅰ、修改表名
如下:
mysql> show tables;
+------------------+
| Tables_in_learn1 |
+------------------+
| u1 |
| user1 |
+------------------+
2 rows in set (0.00 sec)
mysql> alter table user1 rename to user;
Query OK, 0 rows affected (0.01 sec)
mysql> show tables;
+------------------+
| Tables_in_learn1 |
+------------------+
| u1 |
| user |
+------------------+
2 rows in set (0.01 sec)
to
可以省去Ⅱ、新增一列
add
后面跟的是你想新增那一列,列的类型是什么,描述是什么after
表示你想指定新增到那一列的后面注意:插入新字段后,对原来表中的数据没有影响,之前的数据仍然还在
Ⅲ、修改列中某一字段
但是更为重要的是,如果刚才改字段属性就是只改了字段大小,你会发现以前
name
后面的comment
没有了。 说明并不是 定向 你要改那个字段就给你改那个字段,它是把新的属性 直接覆盖 把原来创建name字段,属性等全部覆盖掉。 换句话说如果未来你想改某一列,你肯定要把这一列曾经的所有属性全部复制下来,在代码中对要改的字段修改,在重新提交一下。
Ⅳ、删除列名
alter table user drop password;
**注意:**删除之后,删除字段及其对应的列数据都没了
V、修改列名
将 name 列 修改为 xingming
alter table user change name xingming varchar(60) DEFAULT NULL; # 新字段需要完整定义
说明:
change
后面跟着旧列名 ,再跟新列名和属性。数据类型分类,在MySQL中,每种数据类型都有其特定的用途,类似于我们在学习C/C++等语言时遇到的情形。
以下是一些MySQL中常见的数据类型:
数值类型可以分为以下几类:位类型、布尔类型、整数类型、浮点数类型。
以下主要以整型为例进行说明:
tinyint
、smallint
等,它们根据名称不同,所占的字节数也不同,这些都是MySQL预先定义好的。tinyint
、smallint
等,它们是有符号类型的。其取值范围与C/C++语言中的对应整数范围相同。unsigned
,则表示是无符号类型。以 tinyint
类型为例,其他整数类型的使用方法与此类似。示例语句如下:
create table if not exists t1(num tinyint);
下面查看表的时候,看到
tinyint
后面有一个数字4,这个含义我们将在讨论约束时详细说明,现在先不管
mysql> desc t1;
+-------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------+------+-----+---------+-------+
| num | tinyint(4) | YES | | NULL | |
+-------+------------+------+-----+---------+-------+
tinyint
默认是有符号的,其取值范围是-128~127。超出这个范围的数据将 无法插入UNSIGNED
关键字指定字段为无符号类型。注意:MySQL Server 8.0.17 在不使用 ZEROFILL 修饰符时弃用了 TINYINT.SMALLINT、MEDIUMINT、INT和 BIGINT 数据类型的显示宽度,并且MySQL Server 8.0.19 已从 SHOW 的结果中删除了这些数据类型的显示宽度
创建 无符号 tinyint 类型的表:
create table t2(num tinyint unsigned);
这样就创建了一个num字段为 无符号类型 的表。当插入超出取值范围的数据时,MySQL会拦截,不允许插入。
数据越界测试如下:
mysql> insert into t1 values(-129);
ERROR 1264 (22003): Out of range value for column 'num' at row 1
mysql> insert into t1 values(-128);
Query OK, 1 row affected (0.01 sec)
mysql> insert into t1 values(128);
ERROR 1264 (22003): Out of range value for column 'num' at row 1
mysql> insert into t2 values(128);
Query OK, 1 row affected (0.00 sec)
mysql> insert into t2 values(-129);
ERROR 1264 (22003): Out of range value for column 'num' at row 1
unsigned
,对于 int
类型可能存放不下的数据,int unsigned
同样可能存放不下。int
类型提升为 bigint
类型。⭕ 约束
mysql
特定的类型中插入不合法的数据,MySQL一般都是直接拦截我们,不让我们做越界的操作! 所以 mysql
中,一般而言,数据类型本身也是一种:约束
mysql
也能保证数据插入的合法性。tinyint
为例,它是有符号的,所以可预期的是未来插入的值范围一定在-128~127的。并且数据是完整的没有发生过 截断 或者 隐式类型转化思考:
我们还可以发现一个细节,mysql表中建立属性列, 【列名称在前, 类型在后】 如
num tinyint
如果反过来就是C/C++那一套形式。
语法:bit [ (M) ]
:位字段类型。M表示值比特位的位数,范围从1到64。如果M被忽略,默认为1,示例如下:
create table t3(id int, online bit(1));
使用一个比特位来表示用户是否在线。由于只有一个比特位,只能插入0或1。
ASCLL码值
显示。例如,插入的 0 和 1 在 ASCLL码
中是 不可显示 的,因此查询时可能看不到内容。可以使用 hex
函数 以 16进制形式 显示。语法:float [ (m, d) ] [ unsigned ]
:M指定显示长度,d指定小数位数,占用空间4个字节。创建表示例如下:
create table t4(id int, salary float(4,2));
当然我们还可以创建无符号float类型的表,如下:
create table t5(id int, salary float(4,2) unsigned);
无符号float(4,2)的取值范围是0 ~ 99.99,插入负数将失败。 浮点数在存储时可能会有精度损失。
语法:decimal(m, d) unsigned:定点数m指定长度,d表示小数点的位数
【案例】:
create table t6 (id int, salary float(10,8), salary2 decimal(10,8));
mysql> insert into t8 values(100,23.12345612, 23.12345612);
Query OK, 1 row affected (0.00 sec)
mysql> select * from t6;
+------+-------------+-------------+
| id | salary | salary2 |
+------+-------------+-------------+
| 100 | 23.12345695 | 23.12345612 |
+------+-------------+-------------+
float
类型往往在精度过大或者整体数字过大时会自作聪明帮我们做一些优化策略。decimal
不会,它能够完完全全让数据怎么存就怎么取。decimal
的精度更准确,因此我们如果希望某个数据表示 高精度 ,选择 decimal
语法:char(L)
:固定长度字符串,L是可以存储的长度,单位为字符,最大长度值可以为255。
示例:name char(2)
,表示最多存两个字符。
mysql> create table if not exists t7(id int, name char(2));
Query OK, 0 rows affected (0.04 sec)
mysql> insert into t7 values(1, 'ab');
Query OK, 1 row affected (0.01 sec)
mysql> insert into t7 (id, name) values(1, 'abc');
ERROR 1406 (22001): Data too long for column 'name' at row 1
mysql> insert into t7 (id, name) values(1, '张三');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t7 (id, name) values(1, '张三四');
ERROR 1406 (22001): Data too long for column 'name' at row 1
mysql> select * from t7;
+------+--------+
| id | name |
+------+--------+
| 1 | ab |
| 1 | 张三 |
+------+--------+
2 rows in set (0.00 sec)
MySQL中的字符和C/C++中的字符概念是不一样的,以前语言上的字符,一个字符对应一个字节, 而在MySQL中的字符真的代表一种符号,要么是1234、要么abcd、要么就是中文汉字,一个汉字就是一个字符。 char(2) 表示可以存放两个字符,可以是字母或汉字,但是不能超过2个, 最多只能是255,超过不让你插,连表都不让你建!
🧫 总结:
如下:
mysql> create table t(address char(256));
ERROR 1074 (42000): Column length too big for column 'address' (max = 255); use BLOB or TEXT instead
语法:varchar(L)
:可变长度字符串,L表示字符长度,最大长度65535个字节。
示例:varchar(6)
,表示最多可以插入6个字符。
mysql> create table t8(id int, name varchar(6));
与char的区别:
varchar
是变长字符串,实际使用空间根据字符串长度动态分配,而char
是固定长度。 关于varchar(len)
,len
的值与表的编码密切相关。
mysql> create table t9 (name varchar(21845));
ERROR 1074 (42000): Column length too big for column 'name' (max = 16383); use BLOB or TEXT instead
当我们插入varchar 过长时,会提示 max = 16383,当然有些朋友的 MySQL 是提示的 21844
utf8
MySQL的 utf8
不是真正的 UTF-8
编码
在 utf8
编码中,varchar(n)
的参数n最大值为 21844
MySQL在存储字符类型的时候,认为 utf8
编码,单个字符是三个字节【21845 x 3 = 65535】
varchar
类型 根据实际字符个数动态分配空间,最大字节数 为65535,但需要预留 1-3 个字节用于记录实际字符长度。所以我们上面说的是 21844
证明:
UTF-8
相比于上面 utf8 只能存 3 个字节,utf8m64 可以存 4 个字节,方便存一些emoji符号、一些较复杂的文字、繁体字【都是 4 字节】
我之前还在想,为啥我设置的表是 utf8 字节,但是最后却变成了 utf8mb64,如下:
mysql> create table t(id int) character set utf8;
Query OK, 0 rows affected, 1 warning (0.03 sec)
mysql> show create table t \G;
*************************** 1. row ***************************
Table: t
Create Table: CREATE TABLE `t` (
`id` int DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3
1 row in set (0.00 sec)
ERROR:
No query specified
“utf8mb4”
来支持真正的 UTF-8
现在 MySQL 8.0 之后,默认的数据库字符集已经变成了 utf8mb4
在这里Mark一下:所有在使用“utf8”的 MySQL 和 MariaDB 用户都应该改用“utf8mb4”,永远都不要再使用“utf8”。
总结:
varchar
有自己长度上限,在上限范围内用多少给多少
varchar
最大字节数65535,但65535一定要包含 1- 4 个记录数据长度的字段。在 UTF8
保存在大字符个数是 16383varchar
能到 16383,但是有其他字段那这个值就会变小。char
是定长的,varchar
是变长的。char
一次分配固定空间,varchar
根据实际使用分配空间。实际存储 | char(4) | varchar(4) | char 占用字节 | varchar 占用字节 |
---|---|---|---|---|
abcd | abcd | abcd | 4*3=12 | 4*3+1=13 |
A | A | A | 4*3=12 | 1*3+1=4 |
Abcde | x | × | 数据超过长度 | 数据超过长度 |
如何选择:
定长 VS 变长
常用的日期类型:
date
:日期 ‘yyyy-mm-dd’,占用三字节。datetime
:日期时间 ‘yyyy-mm-dd HH:ii:ss’,表示范围从1000到9999,占用八字节。–手动设置timestamp
:时间戳,从1970年开始的 ‘yyyy-mm-dd HH:ii:ss’ 格式,占用四字节。–自动更新【案例】
mysql> create table t10(t1 date, t2 datetime, t3 timestamp DEFAULT CURRENT_TIMESTAMP);
Query OK, 0 rows affected (0.03 sec)
mysql> desc t10;
+-------+-----------+------+-----+-------------------+-------------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-----------+------+-----+-------------------+-------------------+
| t1 | date | YES | | NULL | |
| t2 | datetime | YES | | NULL | |
| t3 | timestamp | YES | | CURRENT_TIMESTAMP | DEFAULT_GENERATED |
+-------+-----------+------+-----+-------------------+-------------------+
3 rows in set (0.00 sec)
mysql> insert into t10(t1,t2) values('1997-7-1','2008-8-8 12:1:1');
Query OK, 1 row affected (0.00 sec)
mysql> select * from t10;
+------------+---------------------+---------------------+
| t1 | t2 | t3 |
+------------+---------------------+---------------------+
| 1997-07-01 | 2008-08-08 12:01:01 | 2025-02-07 14:00:58 |
+------------+---------------------+---------------------+
注意:timestamp
会自动更新,适用于记录数据的最后修改时间。
要结合具体的场景选择时间:
timestamp
时间戳有什么用呢? datetime
就是要存储一个固定时间,如记录你入职的时间。语法:
enum
:枚举,“单选”类型;enum('选项1','选项2','选项3',...)
set
:集合,“多选”类型;set('选项值1','选项值2','选项值3', ...)
. 说明:不建议在添加枚举值,集合值的时候采用数字的方式,因为不利于阅读
📚 【案例】:
有一个调查表votes,需要调查人的喜好, 比如(登山,游泳,篮球,武术)中去选择(可以多选),(男,女)单选
create table votes(
username varchar(30),
hobby set('clime','swim','draw'), # 注意:使用数字标识每个爱好的时候,想想Linux权限,采用比特位位置来个set中的爱好对应起来
gender enum('男','女')); # 注意:使用数字标识的时候,就是正常的数组下标
mysql> desc votes;
+----------+----------------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+----------------------------+------+-----+---------+-------+
| username | varchar(30) | YES | | NULL | |
| hobby | set('clime','swim','draw') | YES | | NULL | |
| gender | enum('男','女') | YES | | NULL | |
+----------+----------------------------+------+-----+---------+-------+
enum
枚举类型给我提供约束,换句话说插入时只能插入枚举的类型,不允许插入除该枚举类型外其他任何字符。enum
枚举类型在插入的时候,可以直接写这个枚举限定的常量,也可以写对应常量的下标如下:这个数字下标从1开始,分别代表第一个枚举值,第二个枚举值等。有几个就只能到几,超过不行
mysql> insert into votes values('Tom', 'clime', '1');
Query OK, 1 row affected (0.01 sec)
mysql> insert into votes values('Tim', 'draw', '2');
Query OK, 1 row affected (0.01 sec)
mysql> select * from votes;
+----------+-------+--------+
| username | hobby | gender |
+----------+-------+--------+
| Tom | clime | 男 |
| Tim | draw | 女 |
+----------+-------+--------+
2 rows in set (0.00 sec)
① 插入规则
set
以数字形式插入绝对不是下标!
如下:
mysql> insert into votes values('R', '3', '1');
Query OK, 1 row affected (0.00 sec)
mysql> select * from votes;
+----------+------------+--------+
| username | hobby | gender |
+----------+------------+--------+
| Tom | clime | 男 |
| Tim | draw | 女 |
| R | clime,swim | 男 |
+----------+------------+--------+
② SET类型的含义
因此,当我们在向一个 set
集合中插入的时候,这个数字代表的是 位图 。
③ ENUM 与 SET 的区别
enum
和 set
在插入时提供特定的选项,enum
为单选,set
为多选。enum
和 set
的查找可以通过常量或位图进行筛选。enum
中插入数字代表的是 下标,set
中插入数字代表的是位图。在数据库查询中,对于集合类型的字段,可以使用find_in_set函数来进行查询。此函数用于确定一个子串是否存在于一个由逗号分隔的字符串列表中。
find_in_set(sub, str_list):
如果sub在str_list中,则返回子串的位置下标;
如果不在,则返回0;
str_list是由逗号分隔的字符串。
SELECT
语句可以执行表达式,同样,函数也可以执行表达式
mysql> select 1+1;
+-----+
| 1+1 |
+-----+
| 2 |
+-----+
1 row in set (0.00 sec)
mysql> select find_in_set('b','a,b,c');
+--------------------------+
| find_in_set('b','a,b,c') |
+--------------------------+
| 2 |
+--------------------------+
1 row in set (0.00 sec)
mysql> select find_in_set('ab','a,b,c');
+---------------------------+
| find_in_set('ab','a,b,c') |
+---------------------------+
| 0 |
+---------------------------+
1 row in set (0.00 sec)
返回值解释
功能说明
find_in_set
只能用来检查一个元素是否在集合中。应用实例
例如,在查找用户的爱好时,如果是 ‘client’ 或者 ‘swim’ 和 ‘client’,则可以用 find_in_set
来进行严格匹配:
mysql> select * from votes;
+----------+------------+--------+
| username | hobby | gender |
+----------+------------+--------+
| Tom | clime | 男 |
| Tim | draw | 女 |
| R | clime,swim | 男 |
+----------+------------+--------+
mysql> select * from votes where hobby = 'clime';
+----------+-------+--------+
| username | hobby | gender |
+----------+-------+--------+
| Tom | clime | 男 |
+----------+-------+--------+
mysql> select * from votes where find_in_set('clime', hobby);
+----------+------------+--------+
| username | hobby | gender |
+----------+------------+--------+
| Tom | clime | 男 |
| R | clime,swim | 男 |
+----------+------------+--------+
mysql> select * from votes where find_in_set('clime, swim', hobby);
Empty set (0.00 sec)
mysql> select * from votes where find_in_set('clime', hobby) and find_in_set('swim', hobby);
+----------+------------+--------+
| username | hobby | gender |
+----------+------------+--------+
| R | clime,swim | 男 |
+----------+------------+--------+
真正约束字段的是数据类型,但是数据类型约束很单一,需要有一些 额外的约束 ,更好的保证数据的 合法性 ,从业务逻辑角度保证数据的正确性。比如:有一个字段是email,要求是唯一的。
表的约束很多,这里主要介绍如下几个:null/not null、default、comment、zerofill、primary key、auto_increment、unique key
之前把列名称和类型都了解了一下,但是在实际查表得时候它们后面是什么东西呢?今天就来说一说~
null 表示列可以为空,not null 表示列不能为空。
【案例】:
create table myclass(
class_name varchar(20) not null, -- 班级名不为空
other varchar(20));
class_name
列设置了 not null;而 other
列默认允许为空。【查询表】结果如下:
mysql> desc myclass;
+------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| class_name | varchar(20) | NO | | NULL | |
| other | varchar(20) | YES | | NULL | |
+------------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> show create table myclass \G;
*************************** 1. row ***************************
Table: myclass
Create Table: CREATE TABLE `myclass` (
`class_name` varchar(20) NOT NULL,
`other` varchar(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)
ERROR:
No query specified
other
这一列我们是只写了一个 varchar
,没有指定 not null
,默认是 null
的,然后面加了一个 default null
【数据插入】测试:
mysql> insert into myclass values('1班');
ERROR 1136 (21S01): Column count doesn't match value count at row 1
mysql> insert into myclass (class_name) values('1班');
Query OK, 1 row affected (0.01 sec)
mysql> insert into myclass (other) values(102);
ERROR 1364 (HY000): Field 'class_name' doesn't have a default value
mysql> insert into myclass values(NULL, NULL);
ERROR 1048 (23000): Column 'class_name' cannot be null
mysql> select * from myclass;
+------------+-------+
| class_name | other |
+------------+-------+
| 1班 | NULL |
+------------+-------+
1 row in set (0.00 sec)
**注意:**我们对具体某列进行插入时,需要声明该列名字来进行匹配,否则不然就会上面第一行的错误
某列设置了 not null
设置默认为 null
,可以不插用的是后面带的默认值。
default:当插入数据时,如果未指定该列的值,将使用默认值。
【案例】:
create table if not exists student(
name varchar(20) not null,
age tinyint unsigned default 18,
gender varchar(10) default '男'
);
【操作如下】:
mysql> desc student;
+--------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+------------------+------+-----+---------+-------+
| name | varchar(20) | NO | | NULL | |
| age | tinyint unsigned | YES | | 18 | |
| gender | varchar(10) | YES | | 男 | |
+--------+------------------+------+-----+---------+-------+
3 rows in set (0.01 sec)
mysql> insert into student values('RM', '20', '女');
Query OK, 1 row affected (0.00 sec)
mysql> insert into student (name) values('Mike');
Query OK, 1 row affected (0.00 sec)
mysql> insert into student (name, age) values('Mike', NULL);
Query OK, 1 row affected (0.01 sec)
mysql> select * from student;
+------+------+--------+
| name | age | gender |
+------+------+--------+
| RM | 20 | 女 |
| Mike | 18 | 男 |
| Mike | NULL | 男 |
+------+------+--------+
3 rows in set (0.00 sec)
注意:default
和 not null
并不冲突,而是互相补充的。
null
和 not null
约束,要么插 null
,要么插合法数据。 如果建表的时候, 不给某一列添加任何约束,我们会发现MySQL会对sql语句优化,默认会带上 defalut null
。所以不插入的时候在表示会显示 null
comment:用于给列添加注释说明,便于程序员和数据库管理员理解字段用途。
create table if not exists t5(
name varchar(20) not null comment '用户的用户名',
age tinyint unsigned default 18 comment '用户的年龄'
);
zerofill:在数字前补零,使显示字符长度符合指定的位数。
【案例】
mysql> create table if not exists t6(a int unsigned, b int unsigned zerofill);
mysql> show create table t6 \G;
*************************** 1. row ***************************
Table: t6
Create Table: CREATE TABLE `t6` (
`a` int unsigned NOT NULL,
`b` int(10) unsigned zerofill NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)
mysql> insert into t6 values(111, 222);
Query OK, 1 row affected (0.01 sec)
mysql> select * from t6;
+-----+------------+
| a | b |
+-----+------------+
| 111 | 0000000222 |
+-----+------------+
1 row in set (0.00 sec)
zerofill
还是挺形象的,当我们插入 222,前面填满 0.我们再来 按照 16进制 显示,验证一下:值不会改变,zerofill
只是一种格式化输出
mysql> select a, hex(b) from t6;
+-----+--------+
| a | hex(b) |
+-----+--------+
| 111 | DE |
+-----+--------+
1 row in set (0.00 sec)
zerofill
primary key:用于标识表中的唯一记录,不允许重复 或 为空。
创建主键有两种方法:
【案例 1】:创建表的时候就把主键设置好
mysql> create table t7(id int primary key, name varchar(20));
Query OK, 0 rows affected (0.04 sec)
mysql> insert into t7 values(1, 'amy');
Query OK, 1 row affected (0.01 sec)
mysql> insert into t7 values(1, 'anna');
ERROR 1062 (23000): Duplicate entry '1' for key 't7.PRIMARY'
mysql> select * from t7;
+----+------+
| id | name |
+----+------+
| 1 | amy |
+----+------+
主键约束 对于程序员来讲,未来想往这个表里面插对应插入的数据主键列不能冲突,一旦冲突不让你插入,所以倒逼程序员插的时候尽量不要出现 主键冲突 其次站在
mysql
视角凡是插入这个表里面的数据主键一定是不冲突的。这样的好处是根据主键绝对能拿出来确定的一条记录!–唯一性
有了 主键 可以有 针对性 的 对数据进行增删查改
【案例 2】:表建好之和但没有主键,可以追加主键
mysql> alter table t7 drop primary key; -- 删除主键
Query OK, 1 row affected (0.08 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> desc t7;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int | NO | PRI | NULL | |
| name | varchar(20) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> alter table t7 add primary key(id); -- 添加主键
Query OK, 0 rows affected (0.07 sec)
Records: 0 Duplicates: 0 Warnings: 0
【复合主键】
虽然一张表中最多只能有一个主键,但是并不意味着一个表中的主键只能添加给一列!
primary key(主键字段列表)
来创建主键,如果有多个字段作为主键,可以使用 复合主键【案例】下面创建表我们让两列合起来充当一个主键
mysql> create table t8(id int, name varchar(20), primary key(id,name));
Query OK, 0 rows affected (0.03 sec)
mysql> desc t8;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int | NO | PRI | NULL | |
| name | varchar(20) | NO | PRI | NULL | |
+-------+-------------+------+-----+---------+-------+
这里虽然可以看到 id 和 name 都是主键,但是一张表只能有一个主键,我们该怎么理解这个情况?
有两个 PRI,但并不证明有两个主键!而是这两个都是主键,两个都是主键如何理解呢?它们两个合起来才是一个主键!
mysql> insert into t8 values(123, 'zs');
Query OK, 1 row affected (0.01 sec)
mysql> insert into t8 values(156, 'zs');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t8 values(123, 'zs');
ERROR 1062 (23000): Duplicate entry '123-zs' for key 't8.PRIMARY'
但是我们不允许,同一个同学有同一个 id,这就会出现主键约束了。它是把 id 和 name 作为一个整体的。
auto_increment:字段自动增长,从当前最大值加 1,通常配合主键使用,确保值唯一。
自增长的特点:
【案例】:在此示例中,id
列自增长,无需显式插入,系统自动为其赋值。
create table t10(id int primary key auto_increment, name varchar(20));
mysql> insert into t10 (name) values('a');
mysql> insert into t10 (name) values('b');
mysql> select * from t10;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
+----+------+
2 rows in set (0.00 sec)
插入时,我们可以指定插入其他列,id这一列就不管了。可以看到虽然我并没有告诉id要插什么,但是id是自动帮我们插入的,并且是增长的。
mysql> insert into t10 (id, name) values(1000, 'c');
mysql> insert into t10 (name) values('d');
mysql> select * from t10;
+------+------+
| id | name |
+------+------+
| 1 | a |
| 2 | b |
| 1000 | c |
| 1001 | d |
+------+------+
4 rows in set (0.00 sec)
auto_increment
约束外,还可以在表外设置 auto_increment
的值,这代表下一次插入的起始值。create table t11(id int primary key auto_increment, name varchar(20))auto_increment=100;
mysql> insert into t11 (name) values('a');
mysql> insert into t11 (name) values('b');
mysql> select * from t11;
+-----+------+
| id | name |
+-----+------+
| 100 | a |
| 101 | b |
+-----+------+
auto_increment
值,使其成为下次插入的起始值。mysql> show create table t10 \G;
*************************** 1. row ***************************
Table: t10
Create Table: CREATE TABLE `t10` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1002 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
获取上次插入的 AUTO_INCREMENT
值
last_insert_id()
函数来获取最后一次插入的 AUTO_INCREMENT
值。AUTO_INCREMENT
值。mysql> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
| 1001 |
+------------------+
1 row in set (0.00 sec)
还记得上面说 自增长前提是个 索引,我们现在来简单了解一下索引是啥?
索引定义:
索引使用:
**定义:**一张表中有往往有很多字段需要 唯一性 ,数据不能重复,但是一张表中只能有一个 主键,而此时 唯一键 就可以解决表中有多个字段需要唯一性约束的问题。
区别:
示例场景:在员工管理系统中,身份证号码可以作为主键,确保员工的唯一标识;员工工号可以设置为唯一键,确保工号在公司业务上不会重复。
mysql> create table student (
-> id char(10) unique comment '学号,不能重复,但可以为空',
-> name varchar(10)
-> );
mysql> insert into student(id, name) values('01', 'aaa');
mysql> insert into student(id, name) values('01', 'bbb'); -- 触发唯一约束错误
ERROR 1062 (23000): Duplicate entry '01' for key 'id'
mysql> insert into student(id, name) values(null, 'bbb'); -- 允许为空
主键 vs 唯一键
唯一键和主键不冲突,可以理解为对主键的补充设置
只能有一个主键,但可以有多个唯一键
外键:
外键 用于 确保表间数据的一致性,例如:防止插入一个不存在班级的学生或删除一个还有学生的班级。
外键 用于定义 主表 和 从表 之间的关系:
unique
约束NULL
在从表中,设置外键约束:
foreign key (字段名) references 主表(列)
【案例】:
mysql> create table stu(
-> id int primary key,
-> name varchar(30) not null comment '学生名',
-> class_id int,
-> foreign key (class_id) references class(id));
-- 插入班级数据
mysql> insert into class values(10,'1班'), (20, '2班');
-- 插入学生数据
mysql> insert into stu values(1,'1班',10), (2, '2班',20);
-- 插入无效数据
mysql> insert into stu values(30,'1班',3);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`learn2`.`stu`, CONSTRAINT `stu_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `class` (`id`))
如果两张表在业务上是有相关性的,但是在业务上没有建立 约束 关系,那么就可能出现问题
建立外键的本质其实就是把相关性交给MYSQL去审核了,提前告诉 MySQL
表之间的约束关系
,但可以有多个唯一键
外键:
外键 用于 确保表间数据的一致性,例如:防止插入一个不存在班级的学生或删除一个还有学生的班级。
外键 用于定义 主表 和 从表 之间的关系:
unique
约束NULL
在从表中,设置外键约束:
foreign key (字段名) references 主表(列)
【案例】:
mysql> create table stu(
-> id int primary key,
-> name varchar(30) not null comment '学生名',
-> class_id int,
-> foreign key (class_id) references class(id));
-- 插入班级数据
mysql> insert into class values(10,'1班'), (20, '2班');
-- 插入学生数据
mysql> insert into stu values(1,'1班',10), (2, '2班',20);
-- 插入无效数据
mysql> insert into stu values(30,'1班',3);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`learn2`.`stu`, CONSTRAINT `stu_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `class` (`id`))
如果两张表在业务上是有相关性的,但是在业务上没有建立 约束 关系,那么就可能出现问题
建立外键的本质其实就是把相关性交给MYSQL去审核了,提前告诉 MySQL
表之间的约束关系
MySQL
不允许你插入