前言:最近在跟着黑马程序员复习MySQL数据库,因此打算把复习到的东西记录下来,希望对大家有用!(本文内容部分来自黑马程序员的PPT,如有侵权,联系可删)
(本文有一些不易理解得地方,作者都有将自己如何理解的写下来,便于大家理解~)
MySQL的介绍
这一部分,我们先来讲解三个概念:数据库、数据库管理系统、SQL。
数据库:存储数据的仓库,数据在其中是有组织的被存储起来。比如目前互联网上常见的Oracle、MySQL、SQL Server等。
数据库管理系统:用于操纵和管理数据库的大型软件。比如目前常见的Navicat、DataGrip等软件。
SQL:用于操作相关性数据库的编程语言,是操作关系型数据库的统一标准。正是因为有SQL的存在,因此我们学的SQL语句对于各大数据库的操作方式都是一样的,因此不用担心我们学完MySQL后,到了公司是用Oracle或者其他数据库,因为它们的操作方式都是一样的。
SQL语句
SQL:全称 Structured Query Language,结构化查询语言。操作关系型数据库的编程语言,定义了一套操作关系型数据库统一标准 。
2.1 SQL通用语法
在学习具体的SQL语句之前,先来了解一下SQL语言的同于语法。
(1). SQL语句可以单行或多行书写,以分号结尾。
(2). SQL语句可以使用空格/缩进来增强语句的可读性。
(3). MySQL数据库的SQL语句不区分大小写,关键字建议使用大写。
(4). 注释:
①单行注释:-- 注释内容 或 # 注释内容
②多行注释:/* 注释内容 */
2.2 SQL分类
SQL语句,根据其功能,主要分为四类:DDL、DML、DQL、DCL。
DDL:全称“Data Definition Language”,是指用于定义、操作数据库对象(数据库、表、段)的语言。
DML:全称“Data Manipulation Language”,是指用于对数据库表中的数据进行增删改操作的语言。
DQL:全称“Data Query Language”,是指用于查询数据库数据的语言。
DCL:全称“Data Control Language”,是指用来创建数据库用户、控制数据库的访问权限的语言。
了解了SQL语句的分类后,接下来我们会详细介绍SQL语句的语法。
2.2.1 DDL
(1)查询所有数据库
show databases;
(2)查询当前数据库
select database();
(3)创建数据库
create database if not exists 数据库名;
上述语句中有“if not exists”的作用是:如果不存在此数据库就创建该数据库,否则不创建。“if not exists”是可以省略的,但是对于已经存在的数据库,如果继续创建则会报错,因此加上会更加安全。
(4)删除数据库
drop database if exists 数据库名;
这里的“if exists”也是可以省略的,作用和上面创建数据库中的“if not exist”一样。
(5)切换数据库
use 数据库名;
2.2.2 DML
(1)查询当前数据库所有表
show tables;
(2)查看指定表结构
desc 表名;
(3)查询指定表的建表语句
show create table 表名;
(4)创建表结构
create table 表名{
字段1 字段1类型 [约束] [ COMMENT 字段1注释 ],
字段2 字段2类型 [约束] [COMMENT 字段2注释 ],
字段3 字段3类型 [约束] [COMMENT 字段3注释 ],
......
字段n 字段n类型 [约束] [COMMENT 字段n注释 ]
}[ COMMENT 表注释 ] ;
这里的约束和注释可以省略。对于注释大家肯定很了解,就是对于某一行或者某一段的解释。约束是指对于某个字段的要求,具体我们后面会解释。
(5)为已存在的表结构添加字段
alter table 表名 add 字段名 数据类型 [default 默认值] [约束] [comments 注释];
这里指在已存在的表中添加新的字段,用 [ ] 包起来的代表可以省略。
(6)修改表中某字段的数据类型
alter table 表名 modify 字段名 新数据类型;
这里是指将指定字段的数据类型更改为上述的“新数据类型”。
(7)同时修改表中的字段名和字段类型
alter table 表名 change 旧字段名 新字段名 新数据类型
这里指将指定字段的名称修改为新的字段名,并且修改数据类型为上述的新数据类型。
(8)删除表中的某个字段
alter table 表名 drop 字段名
可以删除指定表的指定字段
(9)修改表名
alter table 表名 rename to 新表名
这里可以修改指定表的名称为新表名
(10)删除指定的表
drop table [if exists] 表名
(11)删除指定表,并重新创建一个名字一模一样的空表
truncate 表名
2.2.3 DQL(这个是我们四大分类中的重点,以后我们主要和它打交道)
DQL 查询语句,语法结构如下:
select 查询的字段名 from 表
[where 条件]
[group by 分组依据]
[having 分组后的条件]
[order by 排序依据]
[limit 分页参数]
以上用“[ ]”包起来的不是必须DQL语句必须写的,意思是可以根据自己的需要来判断是否要加以上那些语句。因此,我们在讲解这节内容的时候,,会将上面的完整语法进行拆分,分为以下几个部分:
①基本查询(不带任何条件)
②条件查询(WHERE)
③聚合函数(count、max、min、avg、sum)
④分组查询(group by)
⑤排序查询(order by)
⑥分页查询(limit)
为了方便大家理解,我在自己的数据库中建立了一个名为“cug_user”的表,并插入了如下数据:
![](https://i-blog.csdnimg.cn/blog_migrate/80155fbff124a427d793df6aea67b91b.png)
(部分字段名解释:gender是性别,这里男性为1,女性为2。 status 为所处部门,同样用数字来代替)
2.2.3.1 基本查询(不带任何条件)
由上一节我们知道,SQL语句的基本查询如下:
select 字段名1、字段名2、字段名3......字段名n from 表A
上述SQL语句意思是“从表A中查询出字段名1、字段名2、字段名3......字段名n的值”。
比如:我们这里需要从cug_user表中查询所有人的名字和电话号,我们可以这样写:
select name,phone from cug_user;
查询出的结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/c7e1805876ebfb29f2c2b7c8ca8bec4c.png)
当然,如果我们查询的是表中的所有字段,那么可以将查询的所有字段用“*”来代替:
select * from 表A
上述SQL语句的意思便是“查询表A所有字段的数据”
比如我们要查询cug_user表中的所有字段,那么我们可以这样写:
select * from cug_user;
查询出的结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/386474e8680cbf07b48b0056cb0ac802.png)
2.2.3.2 条件查询(WHERE)
上面我们说了基本查询,那么肯定有同学说了,如果需要加一点条件怎么办呢?比如我们逛淘宝的时候,一般会在搜索框输入一些查询条件或者在分类中选择我们要买的产品分类。这便是条件查询。因此条件查询的语句格式如下:
select 字段名1、字段名2....字段名n from 表名 where 条件
比如我们需要查询cug_user表中所有男性(gender为1)的名字和专业,那么我们可以这样写:
select name,profession from cug_user where gender=1;
查询出的结果为:
![](https://i-blog.csdnimg.cn/blog_migrate/8417d2ff6b25c3505b91549c28766cee.png)
当然,where后面不仅可以只有一个条件,可以跟多个条件,用“and”或者“or”来拼接。
比如,我们需要查询cug_user表中id小于10的所有男性(gender为1)的ID和名字,那么我们可以这样写:
select id,name from cug_user where gender=1 and id<10;
查询出的结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/842fbb1248d206feaf912dafbfb9df05.png)
如果我们想查询cug_user表中id小于10或者性别为女性的所有字段数据时,我们可以这样写:
select * from cug_user where id<10 or gender=2;
查询的结果为:
![](https://i-blog.csdnimg.cn/blog_migrate/95dbf705bfcfa6681f710402680d72fb.png)
2.2.3.3 聚合函数(count、max、min、avg、sum)
我们先要来知道什么是聚合函数,聚合函数是指“将一列数据作为一个整体,进行纵向计算” 。比如我们要计算cug_user表中所有人的年龄之和,我们可以用sum(age)。
常见的这几种聚合函数的功能如下:
![](https://i-blog.csdnimg.cn/blog_migrate/1cb2a81669131d07f1c0af4392231a7c.png)
我们这里拿count 、max、avg来举例子。比如:我们需要查询cug_user表中满足id小于15的人数、这些人的最大ID值、这些人的平均年龄。我们的SQL语句可以这样写:
select count(*),max(id),avg(age) from cug_user where id<15;
查询出的结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/b1570fb37b62ec667d4928b9d60a2a4e.png)
满足条件的一共有14人(id为1~14),最大id为14,平均年龄为33.1429。
这里我们讲一个小语法:“起别名”。从之前的数据以及上图我们可以发现,如果我们就按数据库给我们起的名字(比如平均年龄就是“avg(age)”)这样影响阅读,不了解的人根本不知道这几个字段是干嘛的,因此我们要学会给查询出来的字段起别名:关键字为“as”。基本语法如下:
select 字段1 as 别名1,......,字段n 别名n from 表A
当然,“as”是可以省略的。
比如我们给上述的几个字段取别名,让它们呈现为:“总数”、“最大ID值”、“平均年龄”。我们可以这样写SQL语句:
select count(*) as 总数,max(id) 最大ID值,avg(age) 平均年龄 from cug_user
where id<15;
查询出来的结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/d6f27d19249ad963764d18d7ccbb5bca.png)
可见,我们查询出来的字段可以给它们取别名,不仅自己看着舒服,他人看着也便于理解。同时,as是可以省略的,上述SQL语句我只有第一个写了“as”,后面两个是没写的,但是最好写,这样便于大家理解。
2.2.3.4 分组查询(group by)
那么,我们在平时经常会根据某些东西分组,比如在上幼儿园的时候,分座位的时候,我们老师经常会把我们分成男女生,以便于一男一女的排座位。那么对于数据,我们经常也需要分组,这里就要用到关键字“group by”。
语法如下:
SELECT 字段列表 FROM 表名 [ WHERE 条件 ] GROUP BY 分组字段名 [ HAVING 分组
后过滤条件 ];
这里我们看到,除了多了“group by”以外,后面还跟着一个可选的“having”,这里“having”的作用是,分组后再根据having后面的条件进行过滤,比如:将cug_user表中年龄小于40的数据根据性别和部门(status)分组后,过滤掉分组后的部门人数小于3的数据,查询这两组的总数和平均年龄可以这样写:
select count(*) 总数,avg(age) 平均年龄 from cug_user
where age < 40 group by gender,status having count(status)>=3;
查询出的结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/0bb0780a594a8ff6cbbd86a63d22f61b.png)
这里大家肯定有很疑惑了,having和where的区别是什么?二者区别如下:
①执行时机不同:where是分组之前进行过滤,不满足where条件,不参与分组;而having是分组之后对结果进行过滤。
②判断条件不同:where不能对聚合函数进行判断,而having可以。
这里还有些注意事项需要和大家说一下:
• 分组之后,查询的字段一般为聚合函数和分组字段,查询其他字段无任何意义。
• 执行顺序: where > 聚合函数 > having 。
• 支持多字段分组, 具体语法为 : group by columnA,columnB
这里的执行顺序大家可以和上面二者区别②连起来看:因为where在聚合函数执行之前,当然聚合函数就不能用于where后面的条件过滤了。这里就可以和我们平时的编程语言一样的理解,比如:“在第10行声明的变量,肯定不能在第8行使用”。
那注意事项的第一条:“分组之后,查询的字段一般为聚合函数和分组字段,查询其他字段无任何意义。”是什么意思呢?这里是指,如果我们根据“age”来分组,就只能查询“age”这个字段或者聚合函数的值,并且如果有having来过滤条件的话,也只能根据“age”或者聚合函数值来分组。如果不满足则会报错,比如我们这里将上一条SQL语句改为having后面根据ID来过滤,则会出现以下情况:
![](https://i-blog.csdnimg.cn/blog_migrate/002fdc41820efa8b980cc2fcf2688fd4.png)
总结:因此如果我们用了“group by”,那么我们查询和having过滤的条件只能是我们分组的字段或者聚合函数的值。
2.2.3.5 排序查询(order by)
平时我们网上购物的时候,有时候会给列表数据排个序,比如根据价格从低到高啊,或者根据好评从高到低来排。因此我们查询数据的时候,也需要学会如何排序,这里就要提排序的关键字了“order by”。基本语法如下:
SELECT 字段列表 FROM 表名 ORDER BY 字段1 [排序方式1], 字段2 [排序方式2],.....,字段n [排序方式n];
首先我们平时生活中排序肯定有降序和升序,因此SQL语句也是分降序和升序:
①ASC : 升序(默认值) ②DESC: 降序
如果我们不指定排序方式的话,默认我们使用升序排序。多个字段排序的话,意思是:如果前面的排序字段二者相等,那么才根据此字段排序。
比如:我们从cug_user中查询所有人的数据,根据年龄升序排序,并且如果年龄大小一样的话,就根据ID降序排序。SQL语句如下:
select * from cug_user order by age asc,id desc;
结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/e17608f0dfcc6db36b5b48389e21690b.png)
可见,查询出来的结果按我们的设置,根据年龄升序排序,并且如果年龄大小一样的话,就根据ID降序排序。
2.2.3.6 分页查询(limit)
分页查询也是我们生活中常见的需求,比如我们网上购物的时候肯定有第一页、第二页这样,所以我们查询数据的时候也需要学会使用分页查询,这里又需要知道分页查询的关键字:“limit”。基本语法如下:
SELECT 字段列表 FROM 表名 LIMIT 起始索引, 查询记录数 ;
比如我们查询cug_user中所有人数据,仅显示从索引下标0开始,查询5条,那么SQL语句如下:
select * from cug_user limit 0,5;
结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/1ad7d5aa01ff9885e2281e920e23fb95.png)
这里需要说几个注意事项:
• 起始索引从0开始,起始索引 = (查询页码 - 1)* 每页显示记录数。
• 分页查询是数据库的方言,不同的数据库有不同的实现,MySQL中是LIMIT。
• 如果查询的是第一页数据,起始索引可以省略,直接简写为 limit 10。
分页查询,分页查询,意思就是要分页,那么对于生活中的那种分页,根据注意事项第一条的公式,我们可以推出limit后面的两个参数值。比如每页五条数据,查询第二页的数据,那么根据公式:起始索引=(2-1)*5=5,查询记录数=5;所以SQL语句如下:
select * from cug_user limit 5,5;
![](https://i-blog.csdnimg.cn/blog_migrate/8650c9c482e37776b28e486394673e90.png)
2.2.3.7 SQL语句执行顺序
好了,上述便是DQL语句的所有内容,一起使用如下:
select 查询的字段名
from 表
[where 条件]
[group by 分组依据]
[having 分组后的条件]
[order by 排序依据]
[limit 分页参数]
那么大家肯定很好奇了,这些语句的执行顺序是怎么样的呢?一定是按着上下的顺序来执行的吗?显然不是,它们的执行顺序如下:
①from ②where ③group by ④having ⑤select ⑥order by ⑦limit。
这里也很好理解为什么是这样:“对于一张表,我们肯定先要从(from)哪个表查询,然后过滤条件(where)是什么,如何分组(group by),分组后过滤(having)掉哪些数据,然后得到(select)这些数据,再将这些数据排序(order by),并且分页(limit)查询”。
2.2.4 DCL
DCL英文全称是Data Control Language(数据控制语言),用来管理数据库用户、控制数据库的访问权限。
(这类SQL开发人员操作的比较少,主要是DBA( Database Administrator 数据库管理员)使用,所以大家看看就好。)
2.2.4.1 管理用户
(1). 查询用户
select * from mysql.user;
(2). 创建用户
CREATE USER '用户名'@'主机名' IDENTIFIED BY '密码';
(3). 修改用户密码
ALTER USER '用户名'@'主机名' IDENTIFIED WITH mysql_native_password BY '新密码' ;
(4). 删除用户
DROP USER '用户名'@'主机名' ;
2.2.4.2 权限控制
MySQL中定义了很多种权限,但是常用的就以下几种:
①ALL, ALL PRIVILEGES : 所有权限
②SELECT : 查询数据
③INSERT : 插入数据
④UPDATE : 修改数据
⑤DELETE : 删除数据
⑥ALTER : 修改表
⑦DROP : 删除数据库/表/视图
⑧CREATE : 创建数据库/表
上述只是简单罗列了常见的几种权限描述,其他权限描述及含义,可以直接参考官方文档。
(1). 查询权限
SHOW GRANTS FOR '用户名'@'主机名' ;
(2). 授予权限
GRANT 权限列表 ON 数据库名.表名 TO '用户名'@'主机名';
(3). 撤销权限
REVOKE 权限列表 ON 数据库名.表名 FROM '用户名'@'主机名';
注意事项:
• 多个权限之间,使用逗号分隔
• 授权时, 数据库名和表名可以使用 * 进行通配,代表所有。
数据类型
在上述的建表语句中,我们在指定字段的数据类型时,用到了int ,varchar,那么在MySQL中除了以上的数据类型,还有哪些常见的数据类型呢? 接下来,我们就来详细介绍一下MySQL的数据类型。MySQL中的数据类型有很多,主要分为三类:数值类型、字符串类型、日期时间类型。
3.1 数值类型
![](https://i-blog.csdnimg.cn/blog_migrate/b89e4e3bb56e9f6b28103773d649bfcc.png)
3.2 字符串类型
![](https://i-blog.csdnimg.cn/blog_migrate/4820219b8da173ad7ee174939647f808.png)
3.3 日期类型
![](https://i-blog.csdnimg.cn/blog_migrate/764b22f3a69dfb6f98f27f871c2e9794.png)
函数
函数,类似于我们Java中的方法,是指一段可以直接被另一段程序调用的程序或代码。当然目前我们主要学的是MySQL给我们提供的函数,我们需要明白在具体的地方如何使用这些函数即可。
MySQL中的函数主要分为以下四类: 字符串函数、数值函数、日期函数、流程函数。
4.1 字符串函数
MySQL内置了很多字符串函数,我们常使用的几个如下:
①CONCAT(str1,str2,....,strn) :将多个字符串拼接在一起。
比如我想将字符串“hello”,“mysql”拼接在一起并且查询,可以这样写SQL语句:
select concat('hello','mysql') as 拼接后的字符串;
执行上述SQL语句结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/af8f6f78155c6e80238a4642ecd7f20b.png)
②LOWER(str):将字符串str中的字母全转为小写。
比如我们要将字符串“HELLOMYSQL”这个字符串转为小写,SQL语句如下:
select lower('HELLOMYSQL') as 转换后的字符串;
执行上述SQL语句结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/a4b94be18b3b0619ae9a13187784a73d.png)
③UPPER(str):将字符串str中的字母全转为大写。
比如我们要将字符串“hellomysql”这个字符串转为大写,SQL语句如下:
select upper('hellomysql') as 转换后的字符串;
执行上述SQL语句结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/ff4a1fd58134db6491b76921e3aaf16a.png)
当然,这里我们提一嘴:函数之间是可以嵌套的,但是必须满足作为参数的函数的返回值满足参数的要求。(这里和我们Java这些编程语言函数嵌套执行一样的道理)
比如:我们这边将字符串“hello”和“mysql”拼接起来后转为大写可以这样:
select upper(concat('hello','mysql')) as 嵌套字符串函数;
执行上述SQL语句结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/9635d871e33a9e210e5c79829796342b.png)
④LPAD(str,n,pad):用字符串pad对str的左边进行填充,达到n个字符串长度。
比如我们想对字符串“CUG”左填充“TSJ”来达到长度10,那么SQL语句如下:
select lpad('CUG',10,'TSJ') as 填充后的字符串;
执行上述SQL语句结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/4782695288a0a1474554e42668413f65.png)
⑤RPAD(str,n,pad):用字符串pad对str的右边边进行填充,达到n个字符串长度。
比如我们想对字符串“CUG”右填充“TSJ”来达到长度10,那么SQL语句如下:
select rpad('CUG',10,'TSJ') as 填充后的字符串;
执行上述SQL语句结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/9a346a848da957862ae47b0fc82b532c.png)
⑥TRIM(str):对字符串str首尾去空格。
比如我们想对字符串“ CUG ”去空格,SQL语句如下:
select trim(' CUG ') as 去空格后的字符串;
执行上述SQL语句结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/ea00309fde1c445465bdff45b7d06579.png)
⑦SUBSTRING(str,start,len):返回从字符串str从start位置起的len个长度的字符串。
注意:MySQL中字符串下标从1开始,分页的数据条数从0开始。
比如我们想分别获得字符串“HelloWorld”中的Hello和World,SQL语句如下:
select substring('HelloWorld',1,5),substring('HelloWorld',6,5);
执行上述SQL语句结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/de1a6685186793b29482f562a1cc130c.png)
4.2 数值函数
MySQL中常见的数值函数如下:
①CEIL(num):向上取整。
比如要对值5.1向上取整,则SQL如下:
select ceil(5.1) as 向上取整;
执行上述SQL语句结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/5bfd15547d9dc1cda4373852222e4a69.png)
②FLOOR(num):向下取整。
比如要对值5.1向下取整,则SQL如下:
select floor(5.1) as 向下取整;
执行上述SQL语句结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/2cf736e23aec8638a3ad6c447b81c895.png)
③MOD(x,y):返回x/y的模。
比如我们要返回10/3的模,SQL语句如下:
select mod(10,3) as 模;
执行上述SQL语句结果如下
![](https://i-blog.csdnimg.cn/blog_migrate/ca25292daa3c7b2c5ab9efd4a7b6985f.png)
④RAND():返回0~1内的随机数。
比如我们需要得到一个0~1的随机数,SQL语句如下:
select rand() as 随机数;
执行上述SQL语句结果如下
![](https://i-blog.csdnimg.cn/blog_migrate/c9bc4615f4a3fc53aa9cd5b00238db65.png)
⑤ROUND(x,y):求参数x的四舍五入的值,保留y位小数。
比如我们对值 3.1415926四舍五入,保留3位小数,SQL语句如下:
select round(3.1415926,3) as 四舍五入;
执行上述SQL语句结果如下
![](https://i-blog.csdnimg.cn/blog_migrate/b380f3c29310c27566a0c43f7a766c7b.png)
4.3 日期函数
我们经常插入数据的时候需要用到日期时间,比如插入一个员工信息,我们需要插入他的注册时间,这个时候就需要我们学会使用日期函数。
由于这些都比较简单且很好理解,我们就不演示例子了。
MySQL内置的常用日期函数如下:
①CURDATE():返回当前日期。
②CURTIME(): 返回当前时间。
③NOW():返回当前日期和时间。
④YEAR(date):获取指定date的年份。
⑤MONTH(date):获取指定date的月份。
⑥DAY(date):获取指定date的日期。
⑦DATE_ADD(date, INTERVAL exprtype):返回一个日期/时间值加上一个时间间隔expr后的时间值。
⑧DATEDIFF(date1,date2):返回起始时间date1 和 结束时间date2之间的天数。
4.4 流程函数
流程函数的作用和我们写程序时,代码中经常需要判断一些条件,如果满足某些条件就执行XXX,否则执行XXX。因此MySQL也给我们提供了一些流程函数,我们需要学会他们的使用,以便于满足某些特定需求。
MySQL内置常见的流程函数如下:
![](https://i-blog.csdnimg.cn/blog_migrate/a7504f29b4ed226ed4997a871281c42d.png)
约束
5.1 约束分类
首先,我们需要先来了解一下什么是“约束”?
约束是指作用于表中字段上的规则,用于限制存储在表中的数据;作用是保证数据库中数据的正确、有效性和完整性。
当然,看到这可能大家还是不太理解约束是什么意思,别急,我们先来看一下MySQL中有哪些约束:
![](https://i-blog.csdnimg.cn/blog_migrate/d18966e7af5f1e14bbb30b2c9e41dc52.png)
我们拿非空约束来举例子:如果我们用非空约束来约束某个字段,那如果我们插入数据时,这个字段的值为空,那么会插入失败,报错。
这里我们拿之前建立的“cug_user”表来举例子,我在建表的时候,定义了名字不为空,也就是用非空约束来约束了name这个字段:
![](https://i-blog.csdnimg.cn/blog_migrate/8a12ba68931d6cb1da603eb8f975e2bb.png)
那么,如果我们插入数据的时候,故意将name的值为空,会发生什么呢?
这里我们执行以下SQL语句:(表示给表中插入id为21和name为null数据)
insert into cug_user(id,name) values (21,null)
显然,这个SQL语句是执行失败的,报错信息如下:
![](https://i-blog.csdnimg.cn/blog_migrate/6de254722dc1cc6411109277f853c3e1.png)
翻译过来就是:字段name不能为空(因为我们对name字段使用了非空约束)。
5.2 外键约束
那么,看到这大家应该就对约束有了一个大致的了解了,约束就是用来规定我们字段要符合一定条件的东西。好的,剩下的约束我们都不举例了,但是这里我们需要讲一讲最后一个约束:“外键约束”
外键:用来让两张表的数据之间建立连接,从而保证数据的一致性和完整性。
看到这,大家肯定有点疑惑了,为什么外键能保证数据的一致性和完整性呢?这里我们继续用“cug_user”表来举例。
这里是“cug_user”表的数据:
![](https://i-blog.csdnimg.cn/blog_migrate/fff96ba1272850e8bf58eb8af055c622.png)
在上文中我们提到过,status是指员工所属部门,对应表“cug_dept”的数据为:
![](https://i-blog.csdnimg.cn/blog_migrate/f0d58bc91ae0676356d03b3da3c05830.png)
也就是每个人都有对应的所属部门,比如第一条“祺祺宝”所属部门为“志协”,那么,如果我们删除“cug_dept”表的“志协”这一条数据,那status为5的数据不就无法知道他们是什么部门了吗?这里就失去了数据的完整性和一致性。
但是!如果当我们通过外键将“cug_user”表的“status”字段和“cug_dept”表的“id”字段连接起来后,还能删除嘛?这里我们执行如下语句:
delete from cug_dept where id =5;
会报如下错误:
![](https://i-blog.csdnimg.cn/blog_migrate/c24ffdd310aa571749a48c04704ae671.png)
这句话的意思是:无法删除改行数据,因为cug_user”表的“status”字段和“cug_dept”表的“id”字段有外键约束。
看到这大家应该就明白了:“当用外键对两张表进行约束时,如果删除的某行字段与另一张表所绑定的字段还有值时,无法删除,因此保证了数据的完整性和一致性”。
用人话来说就是因为比如上述“cug_user”表中status字段还有关于5这个值,由于status字段与另一张表的ID字段绑定,因此不能删除“cug_dept”表中id为5的数据。
5.2.1 外键语法
①添加外键
为一张表添加外键有两种方法,第一种是在建表的时候为表添加外键:
CREATE TABLE 表名(
字段名 数据类型,
...
[CONSTRAINT] [外键名称] FOREIGN KEY (外键字段名) REFERENCES 主表 (主表列名)
);
另一种是建表后为表添加外键:
ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY (外键字段名)
REFERENCES 主表 (主表列名) ;
比如上述我们为“cug_user”表的“status”字段与“cug_dept”表的“id”字段添加外键,SQL语句如下:
alter table cug_user
add constraint fk_user_dept_id foreign key (status) references cug_dept(id);
这里我们要注意:添加外键的两个字段数据类型必须一样。
②删除外键
ALTER TABLE 表名 DROP FOREIGN KEY 外键名称;
比如我们要删除上述外键,SQL语句如下:
ALTER TABLE 表名 DROP FOREIGN KEY fk_user_dept_id;
5.3 约束的删除/修改
添加了外键之后,再删除父表数据时产生的约束行为,我们就称为删除/更新行为。具体的删除/更新行为有以下几种:
![](https://i-blog.csdnimg.cn/blog_migrate/3129e6dfcbbc6881e79b9a1bebdaa94c.png)
具体语法为:
ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY (外键字段) REFERENCES
主表名 (主表字段名) ON UPDATE CASCADE ON DELETE CASCADE;
(由于大多情况下我们都直接在可视化操作界面直接添加约束或者修改、删除约束,因此上述关于操作约束的指令大家有个印象就行,不用死记)
多表查询
我们之前在讲解SQL语句的时候,讲解了DQL语句,也就是数据查询语句,但是之前讲解的查询都是单表查询。但是在日常使用中,很多时候我们需要多表联查,比如上述如果我们不知道“cug_user”的“status”字段对应值是什么意思,但是我们就是需要查找文体部的所有人名字,我们应该怎么办呢?这里就涉及多表联查,我们下面会说。
6.1 多表关系
在学习多表联查前,我们需要知道表结构之间的关系有哪几种,在我们开发过程中,表结构之间的关系主要分为三种:①一对一。 ②一对多(多对一)。 ③多对多。
6.1.1 一对一
一对一,顾名思义就是表结构之间的数据是一对一的。比如现在有两张表,表A存储宿舍的床位号和身份证号,表B存储身份证号和姓名。那么可见,表A和表B之间数据的关系就是一对一的关系,因为一个人只能有一个床位,一个床位只属于一个人。
6.1.2 一对多(多对一)
一对多(多对一),意思就是表结构之间可能是一行数据对应多行数据,也可能多行数据对应一行数据。比如我们上述的“cug_user”表和“cug_dept”表之间,数据就是多对一的关系,因为“cug_user”表中多个人可以属于同一个部门,一个部门可以包含多个人。
6.1.3 多对多
有了前面两个的概念,“多对多”大家应该也能想到了吧,多对多的意思可以理解成表A中的一条数据可以对应表B中的多行数据,表B中的一行数据也可以对应表A中的多行数据。我们生活中具体的多对多的例子比如:“学生与课程的关系,一个学生可以选修多门课程,一门课程也可以供多个学生选择”。
6.2 多表联查
在理解了表结构之间的关系后,我们就可以来开始说说多表联查了,表与表之间联系起来的关系可以分为三种:①内连接 ②外连接 ③自连接。
原来查询单表数据,执行的SQL形式为:
select * from cug_user;
那么我们要执行多表查询,就只需要使用逗号分隔多张表即可,如:
select * from cug_user ,cug_dept;
具体的执行结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/b3c00cf22a70775ce272d7d02166247b.png)
此时,我们看到查询结果中包含了大量的结果集,总共120条记录,而这其实就是“cug_user”表与“cug_dept”表的笛卡尔积。
但是,上述很多记录是没用的,我们只是需要对应部门的信息。在SQL语句中,如何来去除无效的笛卡尔积呢? 我们可以给多表查询加上连接查询的条件即可。
6.2.1 内连接
内连接:相当于查询A、B交集部分数据。
内连接可以分为隐式内连接:
select * from 表A,表B where 条件
显式内连接:
select * from 表A [inner] join 表B on 条件
6.2.2 外连接
左外连接:
SELECT 字段列表 FROM 表1 LEFT [ OUTER ] JOIN 表2 ON 条件 ... ;
左外连接相当于查询表1(左表)的所有数据,当然也包含表1和表2交集部分的数据。
右外连接:
SELECT 字段列表 FROM 表1 RIGHT [ OUTER ] JOIN 表2 ON 条件 ... ;
右外连接相当于查询表2(右表)的所有数据,当然也包含表1和表2交集部分的数据
6.2.3 自连接
自连接查询,顾名思义,就是自己连接自己,也就是把一张表连接查询多次。我们先来学习一下自连接的查询语法:
SELECT 字段列表 FROM 表A 别名A JOIN 表A 别名B ON 条件 ... ;
而对于自连接查询,可以是内连接查询,也可以是外连接查询。
番外话:基础篇算告一段落啦,接下来有空的时候会陆续给大家更新关于MySQL各个特性的原理。