前言
虽然在大一下学期,就已经接触到了MySQL,但是那个时候只是会用MySQL进行增删改查,在大三上学期,尝试投简历寻找实习时,对方公司对于程序员的MySQL水平有很高的要求,所以我开始系统化的学习MySQL。顺便将整理出的笔记逐步写入博客中,日积月累,准备发表一篇长篇博客。
本篇博客的特点
本篇博客,我会以一个学过的人的身份给大家来讲,所以里面很多部分我会以教师与学生的视角来书写。这可能也会让大家比较可以接受。
MySQL的重要性
MySQL的重要性-SQL写的好,工作随便找。
可以看出其实在现在的工作中,很多的软件app都选择了MySQL作为数据存储的工具。但是光学语法有用么?固然学会了语法非常重要,但是实际上,MySQL在使用时的提速也非常的重要。大量的数据在处理的时候,都需要用一些算法对搜索等过程进行优化。
举个栗子,假设有100万条数据,现在让你进行查询操作,如果不用任何的技巧,我们的思路就是直接一个循环,对内部数据进行遍历,这样的速度可想而知。那么如果使用算法进行优化,那么速度就会有所提升。这也是很多大厂目前数据库操作中最为常见的现象。数据量大,需求响应时间短。
数据模型
下图是MySQL的数据模型,我们就是客户端,通过DBMS创建数据库,再从数据库中创建数据表。当然一个数据库可以创建多个数据表。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cW6qwk4X-1667577677143)(https://note.youdao.com/yws/res/1/WEBRESOURCE0301c28c7ad0bceb41f8ffc984f66111)]
SQL通用语句
- 首先SQL语句可以单行书写,同时也支持多行书写,以分号作为结尾。
- SQL语句可以使用空格/锁进来增强语句的可读性。
- MySQL数据库的SQL语句不区分大小写,但是关键字一般建议大写。
- 注释:
- 单行注释: # 注释内容 或者 – 注释内容
- 多行注释: /* 注释内容 */
SQL分类
分类 | 全称 | 说明 |
---|---|---|
DLL | Data Definition Language | 数据定义语言,用来定义数据库对象(数据库,表,字段) |
DML | Data Manipulation Language | 数据操作语言,用来对数据库表中的数据进行增删改 |
DQL | Data Query Language | 数据查询语言,用来查询数据库中的记录 |
DCL | Data Control Language | 数据控制语言,用来创建数据库用户,控制数据库访问权限 |
数据库操作
查询
查询所有数据库
我们在服务器或者本地搭建数据库服务之后,我们可以创建很多的数据库,但是数据库有很多了之后我们需要实时的知道都有哪些,因为他们的数据库名称不同,所以我们要使用下面的语句。
SHOW DATABASES;
可以看到在写好这个语句之后,我们所有的数据库都会显示出来。
查询当前数据库
SELECT DATABASE();
创建
CREATE DATABASE [IF NOT EXISTS] 数据库名 [DEFAULT CHARSET 字符集] [COLIATE 排序规则]
我们通过上面这句话可以创建一个新的数据库。当然IF NOT EXISTS可以帮我们判断是否存在这个数据库。当存在此数据库时,将不会产生任何操作,在不存在此数据库时,才会创建一个全新的。同时我们MySQL的编码格式不建议使用utf8的格式,我建议使用utf8mb4.
删除
DROP DATABASE [IF EXISTS] 数据库名;
通过上面的语句也可以达成删除的效果。
删除并重新创建表
TRUNCATE TABLE 表名;
使用
USE 数据库名
数据表操作——查询
查询当前数据库中所有的表
SHOW TABLES
上面的代码操作时对数据库中表数据的遍历显示,在运行后,可以显示出当前数据库内,所有的数据表。
查询表结构
DESC 表名
在对表数据的结构进行查询之后,可以看到表中存在一个name的列名,同时数据类型是varchar类型。可以为NULL等等信息。
查询指定表的建表语句
SHOW CREATE TABLE 表名
然后我们可以通过上面的语法,了解如何创建一个表,使新的表的结构,字符完全一致。
数据表操作——创建
创建表
CREATE TABLE 表名 (
字段1 类型 COMMENT '注释',
字段2 类型 COMMENT '注释',
字段3 类型 COMMENT '注释',
字段4 类型 COMMENT '注释'
)
我们通过上面的语法变化我们想要的数据结构来进行创建,可以看到在执行之后,一个符合我们预期效果的表数据就出现了。
数据表操作——数据类型
MySQL中主要支持三大类型,数值类型,字符串类型,时间日期类型。
数值类型
- TINYINT 就是1个字节的整型数据。
- SMALLINT 就是2个字节的整型。
- MEDIUMINT 就是3个字节。
- INT 正常大小的整型,占用4个字节。
- BIGINT 就是很大的整型,占用8个字节。
- FLOAT 单精度浮点数值
- DOUBLE 双精度浮点数值
- DECIMAL 小数值
举个例子,我们在存储某个人年龄时,因为人分的年龄不会超过255,所以可以使用TINYINT类型,同时又因为人的年龄不存在负数,所以使用unsigned,也就是无符号类型。
字符串类型
这里我们需要区分的就是text和blob,首先text就是存储文本,这个大家应该并不陌生,但是blob是用来存储二进制文件的,很多时候,人们将图像传输到数据库,就是使用的blob,同样一些软件安装包也是这种效果,因为这样效率不高,也不好管理。
然后我们区分一下char和varchar。首先char使是定长,也就是说,假设我想存储一个1,那么用char的化,占用10字节,其余九个位置用空格来占用。如果是varchar那就只占用1个字节。
日期时间类型
这里没有太多要解释的,我们一般不使用最后一种类型。
数据表操作——修改
添加字段
ALTER TABLE 表名 ADD 字段名 类型(长度) [COMMENT 注释] [约束];
可以看到我们向demo2中添加一个nickname的列信息,执行后就出现了nickname。
修改数据类型
ALTER TABLE 表名 MODIFY 字段名 新数据类型(长度);
在输入上述语句后,我们成功将nickname字段的数据类型修改为char类型。长度是10个字符。
修改字段名和字段类型
ALTER TABLE 表名 CHANGE 旧字段名 新字段名 新数据类型(长度) [COMMENT 注释] [约束];
在经过上面的操作之后,我们的nickname成功的更改为new_nickname,并且转换为了50字符长度的varchar类型
删除字段
ALTER TABLE 表名 DROP 字段;
在上面的语句执行后,我们就可以删除掉new_nickname字段。
修改表名
ALTER TABLE 表名 RENAME TO 新表名;
这样我们就可以表demo2转化为demo3
数据表操作——插入
给指定字段添加数据
INSERT INTO 表名 (字段1, 字段2, ...) VALUES (值1, 值2, ...);
那么我们可以先来看一下这个语句,首先字段1,字段2就是想要操作的位置,那么和C语言中的格式化很像,我们要将值1和值2对号入座,放入对应的字段中,实现插入的效果。那么我们来看一下实际操作。
这里我们要注意数据类型中,字符类型就要用单引号,那么数值类型的话,就不可以使用单引号。
给全部字段添加数据
当我们明确要给所有字段添加数值时,其实就是添加一整条新的数据,那么我们可以简化我们之前的SQL语句。因为我们不需要去考虑那些要添加,哪些不添加了,所以我们只需要按照数据库中字段顺序进行书写就可以了。
INSERT INTO 表名 VALUES (值1, 值2, ...);
现在我们可以看到这样语句更加简单,也很容易理解。
批量添加数据
INSERT INTO 表名 (字段1, 字段2, ...) VALUES (值1, 值2, ...),(值1, 值2, ...);
INSERT INTO 表名 VALUES (值1, 值2, ...),(值1, 值2, ...);
上面就是批量添加数据的操作,我们可以理解为,批量添加数据就是,在添加一条数据的后面再加上一组或更多组。这个语句就不在展示范例了。
注意
- 插入数据时,指定的字段顺序需要与值的顺序是一一对应的。
- 字符串和日期类型要用单引号括起来。
- 插入的数据大小,应该在字段的范围内。
数据表操作——修改
修改数据
UPDATE 表名 SET 字段名1=值1, 字段名2=值2,.....[WHERE 条件];
我们可以发现更新数据时,set后面不需要括号,只需要用逗号隔开就好。当然后面的WHERE条件也不是必要的,当我们不加入条件时,我们的更改就会覆盖整个表。下面我们来看一下样例。
可以看到我们的loading名字被修改成了wow。这个就是我们的更改方法。
删除数据
DELETE FROM 表名 [WHERE 条件]
这个就是我们删除数据的一个语句,我们只需要将数据进行一个限定就可以做到精确删除摸一个值的位置,那么那一整行就被我们删除掉了。下面我们来看一下样例。
不难看出create的数据被我们删除了。
数据表操作——查询
首先我们要知道,在我们平时生活中,数据库中业务量最高的操作就是查询操作,也就是我们的SELECT操作。当然再MySQL中查询也有很多的方式,我们这一次都要学习,但是我就不像之前一样给大家写一个大的总结了,我们直接来分块学习。
基本查询
查询单个字段或多个字段
其实基本查询就是我以前最为常用的,简单粗暴的方式啊,直接查询整个数据表。我们有两种写法,第一种就是分字段,只搜索我想要的字段,还有一种就是全部搜索,不管是什么字段,我全都进行搜索。
SELECT 字段1, 字段2, ... FROM 表名;
SELECT * FROM 表名;
这就是我说的两种写法的规范方式,第一个我们输入我们想要查询的字段,然后说明要在那个数据表中进行操作,就可以得到结果。第二个就是我要表明我要查询的表名,然后就可以获取表中所有字段的所有数据。下面我们来看一个示例。
我们可以看到再搜索了一个姓名的字段之后,我们的数据库给我们返回了一个字段下的所有的数值。
上面就是完全查询的写法。可以发现它可以自动返回所有字段的所有数据。
设置别名
SELECT 字段1 [AS 别名1], 字段2 [AS 别名2], .... FROM 表名;
那么这个别名到底有什么意义呢?在平时的使用时又有什么用处。我们来做一个对比。首先,平时我们搜索一列数据,返回的结果如下图。
看起来非常的正常对吧,但是我们想想,当一次搜索好多列,这些字段你还看的明白是什么意思么,可能也看的明白对吧,但是如果我们把它变成中文之类的方便理解的名字是不是更好?如下图
这个时候我们返回的结果就是姓名。是不是一眼就看懂了。
去除重复记录
SELECT DISTINCT 字段列表 FROM 表名;
那么去除重复记录有什么用处呢?我们举一个例子,我们现在公司要统计,员工们户籍所在地在哪里,那么是不是会有重复的现象,但是我现在只需要知道,有的员工再北京,有的员工再上海就可以,不需要知道是谁。所以重复的记录就没有意义了,那么我就可以再数据库中进行去重操作。
可以看到上面图片中,我们在进行年龄的搜索,但是年龄的重叠太大了,所以我要进行去重,那么使用了DISTINCT之后,得到的数据就是去重后的数据了。
条件查询
SELECT 字段1, 字段2, ... FROM 表名 WHERE 条件列表;
上面这个就是我们的条件查询,也是非常常用的一种查询方式,其实在很多的项目中,我们都会有查询的条件的。例如,我今天要筛选男生的人员信息,那么我现在就会对性别进行条件筛选。
其实在条件列表中,有很多的查询限制方式。如下图
那么这些运算符都是什么意思呢?我们来看一下。
首先大于号,大于等于号,小于号,小于等于号,等于,不等于这几个都是非常常见的运算符,我们不过多去解释。
BETWEEN ... AND ...
这个是筛选范围的运算符,可以理解为介于哪两个值之间,注意左侧为最小值,右侧为最大值。IN(...)
其实这个运算符,经常使用Python的程序员应该都知道,简直不要太好用,直接就可以知道一个东西是否在一个序列中。
-LIKE
占位符,我们可以理解为C语言中的%d %c这样的东西,但是还存在一些区别,因为它可以用%,同时也可以使用_(下划线).下划线只能匹配一个字符,百分号可以匹配很多个,例如我现在有一个词典,里面有一个单词叫abandom,那么当你用下划线匹配时,_bandom
就可以搜索到,但是要是使用百分号的话,可以这样%bandom
或%andom
或a%om
或ab%dom
等等都可以搜索到。IS NULL
这个可以用来判断一个字段对应的值是不是NULL
。很好理解的。AND
或者&&
这个就是C语言和Python都涵盖了的,&&我相信大家不陌生吧,AND和&&意思是一样的,它可以连接两个条件,当两个条件都满足时,就可以满足判断查询条件了OR
或者||
这个就是或者的意思,也就是说两个条件中有一个满足即可NOT
或!
这个就是非,不是的意思。那么当我们的判断条件不满足时那就触发了这个非的意思。
下面我们来实际操作一下,我们先尝试使用比较运算符,首当其冲的肯定是我们的大于,等于,小于,不等于这些对吧。那么我们来看一下下图的语句。
我们写了一个搜索语句,里面搜索的目标是年龄等于12的人,那么得到的结果就是两个人的完整的数据信息。这句话中,唯一的条件语句就是年龄等于12。那么其他的我们就先跳过了,没必要一个一个的展示。
下面我们来看一下IS NULL的情况,首先IS NULL不用多说,就是一个简单的是否为NULL的判断语句。那么我们直接进行搜索就可以了,结果如下图。
然后我们来看一下Between and的语法结构。这个语法其实就是一个范围,我们也可以用and来进行替代,但是既然可以用官方的,为啥要自己写,虽然不多,但是麻烦(就是懒得写).
最后也是最终的就是这个LIKE,因为其他的都是很好理解的,LIKE有的同学看过了解释之后,并没有看明白。那我们再单独的去看一下这个东西。
上面这个语句我们使用的时%通配符,这个就是一个可以匹配一串字符的匹配符号。所以只要首字母是w的,不管后面有多少字符,都可以被搜索出来。
但是这个就不像%这样了,因为他只能匹配一个字符,也就是说,首字母为w,并且后面只跟着一个字符的才会被搜索出来。
聚合函数
聚合函数在MySQL中,可以将一列字段当作一个整体,进行计算处理。具备的操作函数如下图。
上面的图片中的这些函数操作,可以直接作用于我们的字段进行操作。那么怎么去书写呢?
SELECT 聚合函数(字段) FROM 表名
可以看到刚刚我们的聚合函数直接用括号括住了字段。那么现在让我们来看一下,样例如下。
上面的语句中使用了count函数,可以对搜索到的结果进行计数,最后我们就可以获取到搜索到的数据的条数。
下面我们来学习一下max函数,这个函数可以将搜索到的结果的最大值返回出来作为搜索的结果。下面我们来看一下示例。
我们对人员的年龄进行搜索,最后将搜索到的结果数据,通过聚合函数MAX,求出结果中的最大值。
然后就是min函数,这个函数可以将搜索到的结果的最小值返回为结果,跟max恰巧相反。样例如下。
最后就是avg函数和sum函数,一个是求平均值,另一个是求和,这两个的问题都不是很大,和前面的操作是一样的。这里就不再过多解释。
分组查询
SELECT 字段列表 FROM 表名 [WHERE 条件] GROUP BY 分组字段名 [HAVING 分组后过滤条件]
首先我们可以发现在这个语句中,出现了两种限制条件,一个是WHERE,另一个是HAVING。那么这两个东西有什么区别呢?
- 首先,WHERE是在分组操作前进行的条件筛选,HAVING是在分组后的再次筛选。
- 其次,WHERE条件筛选时不可以使用聚合函数的,HAVING是在可以进行聚合函数筛选的。
那么我们来举一个例子。在公司中,有时候会来进行统计,不同年纪的员工都有多少人。然后进行数据分析。当然我们不需要去做数据分析,我们只需要能统计出来不同年纪的员工有多少人就可以了。那么怎么做呢?来看一下样例。
上面的样例中,我们对年龄进行了分组,同时用聚合函数进行了计数,但是如果只通过计数进行显示,我们无法获取对应的年龄段。所以我们要通过age进行检索,让结果实现一一对应的效果。
那么假设我们要想知道男生或者女生的年龄对应关系呢?其实就是加一个where的限制条件就可以了。示例如下。
从这里我们可以看出来,我们的where条件语句会将我们的搜索结果优先筛选出来,然后再把筛选的结果进行分组。
最后我们来举一个难一点的例子,我们要筛选出所有年龄段中人数大于1的数据。那要如何去筛选。说白了就是我们要对count聚合函数的结果进行一个判断,那么我们可以在group by分组后面写一个简单的having条件判断语句。下面我们来看一下例子。
我们来看一下示例,首先我们将age和count聚合的结果一起进行查询,同时将聚合函数的结果放入age_count中,再在having中进行判断。得到的结果就是题目要的数据。
排序查询
排序查询也是我们生活中非常常用的排序方式,因为我们在某宝,某东等大的网上商城中,筛选价格,筛选品牌这些操作,多多多少少涉及到排序算法。那么我们如何给我们的数据进行排序呢?我们先来看一下语法。
SELECT 字段列表 FROM 表名 ORDER BY 字段1 排序方式1, 字段2 排序方式2;
那么排序方式都有哪些呢?
- ASC 升序(默认值)
- DESC 降序
但是我们的语法中,有时候真的会写好多个字段的排序方式呀,那怎么办?
其实在MySQL中它会根据第一个的排序规则来排序,但是如果第一个字段完全一致,那么我们的电脑会自动根据我们的下一个排序字段进行排序判断。所以才会出现多个字段的排序问题。
那么我们先来看一个简单的示例,首先我们要获取到所有学生的年龄顺序,如果年龄相同就看他们的序号顺序来排列,年龄高的在上面,编号靠前的在上面。
我们的语句就是这样的,首先查询出来对应的id name age 这三个字段,然后我们对age进行降序排列,这样就可以让年龄大的在前面,但是当年龄相同时,我们要进行id的升序排列,这样就可以让id靠前的在上面了。
分页查询
分页查询就是第几个到第几个是一页,后几个到后几个是第二页。其实就是在一个范围内进行操作的意思。那么他的语句逻辑就是
SELECT 字段列表 FROM 表名 LIMIT 起始索引 查询记录数;
那么有几点时需要注意的:
- 首先我们每一页的起始索引是查询的页码数-1后乘上我们的每页显示的数据个数。
- 如果查询的是第一页数据的话,我们可以省略掉起始索引,直接简写成limit 记录数
那么下面我们来看一个示例,首先我们想查表里的数据,想进行分页,我想5个数据一页,那么我想看到第一页的数据。
我们搜索了所有的数据,因为是第一页所以不需要写起始索引,直接写limit 5就可以了。
那么下一个问题马上就来了,如果我想看第二页呢?我们继续看一下示例部分。
我们现在来看一下上面的示例,我们要将搜索的结果进行分页,已知我们要看第二页的数据,那么我们要进行一个计算,(页码-1)*每页的数据数量。这就是我们的起始索引,所以这个题目中我们的起始索引为5.
执行顺序
在MySQL中,也是存在执行顺序的,我们的代码会根据执行的顺序来进行,而不是从左向右依次执行的顺序。不难发现,MySQL优先执行FROM,因为FROM会知道你要从哪个表中进行操作,在这个时候我们就可以给表起一个别名,方便后续书写的时候太过于麻烦了,其次WHERE是第二优先的,因为在查询中,无论是分组还是分页还是分组后的条件,他们的前提都是数据经过了第一轮的筛选,这个也是合情合理的,之后就是GROUP BY 因为在筛选之后,进行分组让数据更加清晰明了,然后就是在分组后的筛选过滤,MySQL对整个数据再一次进行过滤,之后我们才开始查找东西,查找到的东西也是通过前面所有的过滤得到结果,得到的结果再进行一个排序,有需要的进行一个分页,所以整个逻辑非常严谨。这就是MySQL的执行顺序。
函数
什么是函数?
函数是指一段可以直接被另一段程序调用的程序或代码。
在一些特定需求时,数据库表中存储了一个人入职当天的日期,例如2000-11-12,那么你怎么计算他入职的天数呢???
数据库表中,存储了学生的分数值,如99,85,66,那么我们应该怎样做,才可以快速的判定分数等级呢?
那么这些都是要使用函数的。这里我们的函数分为四个结算,分别是:
- 字符串函数
- 数值函数
- 日期函数
- 流程函数
字符串函数
MySQL中内置了很多的字符串操作函数,但是常用的是下面这几个函数。
我们现在开始一个一个的看这些函数:
- CONCAT函数 这个函数可以让多个字符串进行拼接,返回得到的结果。
- LOWER函数 熟悉Python的应该知道,Python中也有一个lower函数。而且他们的作用是相同的,都是将字符串中所有的字符变成小写字符。
- UPPER函数 可以将字符串中所有的字符全都转化为大写字符。
- LPAD函数 我们传入一个待填充的字符串,预期的长度,延伸使用的字符,当字符串不满足这个长度时,会根据我们传入的填补使用的字符在字符串的左侧进行填充来将当前字符延伸为目标长度。
- RPAD函数 我们传入一个待填充的字符串,预期的长度,延伸使用的字符,当字符串不满足这个长度时,会根据我们传入的填补使用的字符在字符串的右侧进行填充来将当前字符延伸为目标长度。
- TRIM函数 这个函数可以将字符串头部和尾部的空格删除。
- SUBSTRING函数 这个函数需要传入字符串和其实位置和终止位置,他可以返回这个区间的字符串。
现在我们来看一些例子:
首先是我们的CONCAT函数的写法,这个函数可以将多个字符串进行拼接,所以我们直接做一个将每一个用户的姓名和年龄拼接起来的函数。示例如下:
下一个函数是LOWER函数,这个函数可以将所有字符串中的大写字符变成小写字符,下面我们来将所有用户的名字变为小写。大家可以先将数据中的一些字符变成大写的,然后测试代码。下面是样例部分。
下面我们来看一下upper函数,这个函数可以将所有的字符转化为大写字符。现在我们实现一下将所有用户的名字转化为大写。记得哦!是转化出来,不是之前的搜索。所以我们要使用的是UPDATE函数。在更新之后我们再来搜索一下。
然后是LPAD函数和RPAD函数,我们首先要知道,他们的作用就是用我们想使用的字符延伸字符串到我们想要的长度。那么我们可以来将所有的人员姓名对齐为3个字符。下面我们来看一下示例。
注意事项:
当我们想要左对齐的字符数并不是现有字符串中最大的字符数,例如:我们的数据中有的名字是3个字符的,但是我们想要1个字符左侧对齐,就会出现一个BUG。我们来看一下下面的代码。
我们会发现三个的或者两个字符的名字数据,全都被剪切开了,所以这个问题是我们要去注意的。
下面我们继续学新的函数,TRIM函数。这个函数可以清除掉字符串的开头和结尾部分的空格。是一个很方便的函数。那么我们现在先用更新函数将每一个人的名字前面都加上空格,然后再通过这个函数来删除掉他们。然后搜索一遍。示例代码如下:
最后就是我们的SUBSTRING函数了,这个函数的用处就是将一个范围内的字符串返回出来,下面我们返回一下,一个范围内的人员姓名。
我们会发现有的用户名字只有一个字符,但是我想输出他两个字符,那么也不会报错。
数值函数
那么我们现在已经学完了字符串的函数,现在让我们来学习一下什么是数值的函数。首先我们看一下下面的表格。
下面我们来进行一下数值函数的讲解:
- CEIL函数 可以将数值向上取整,得到一个大于当前数值的整数数据
- FLOOR函数 可以将数值向下取整,得到一个小于当前数值的整数数据
- MOD函数 这个函数,接受两个参数(x, y),得到的结果就是x/y的模
- RAND函数 返回0-1内的随机数
- ROUND函数 函数接受两个参数(x, y),求参数x的四舍五入的值,保留y位小数
上面就是几个我们常说的函数。下面我们来一个一个学习一下。
首先是CEIL函数,这个函数可以进行向上取整的操作,那么我们现在在原有数据中添加一个新的字段,人员分数,这个字段是一个double类型,我们要将他们的分数查询出来并进行向上取整。先来看一下示例。
不难看出,上面的示例代码中,进行了搜索,查询了用户名称和他的成绩的向上取整的结果。
下面就是使用FLOOR函数的结果,数据进行向下取整,可以看一下这个示例代码。
可以看到所有的数值,整体向下取整。
下面我们来看一下MOD函数,这个函数的取模操作,大家一定都知道吧。看一下下面的示例。
可以看到上面的示例中进行了,10/3的取模操作。
rand函数没有太多要说的,就是一个取0-1之间的随机数的函数,我们看一下效果。
最后是ROUND函数,是一个四舍五入的函数。第一个参数为数值,第二个参数为取几位。
可以看到样例中,将我们表中的所有分数都进行了取一位的操作。
流程函数
先写到这里吧。。。。等到下一篇文章,我们继续。