452 lines
19 KiB
Markdown
452 lines
19 KiB
Markdown
---
|
||
layout : post
|
||
title : "MySQL基础篇"
|
||
subtitle : "Database is all"
|
||
date : 2022-06-18 09:58:06
|
||
author : "Manford Fan"
|
||
catalog : false
|
||
header-img : "img/post-bg-universe.jpg"
|
||
tags :
|
||
- Database
|
||
- Mysql
|
||
---
|
||
|
||
前段时间查日志的时候,XLC跟我说有时间学习下SQL,日志平台支持了SQL语句,比较好用,我说好的,可直到现在我也没有去平台看过。最近做了一个一键复原VPS脚本,作用是根据之前的备份,通过执行bash脚本,完成之前环境的完全恢复,包括nginx,jekyll,sql(for cloudreve&nextcloud),php以及各种文件配置等。备份恢复SQL的时候只是备份的对应数据库,发现用户总是没能备份恢复成功,所以想系统的学习下SQL这门语言,想找到其中的原因,顺便更新下自己的技能树,为了更好地搬砖~
|
||
|
||
|
||
## 一、MySQL概述
|
||
|
||
和MySQL相关的观念基本有三个:数据库,数据库管理系统以及SQL。数据库(database,DB)是存储数据的仓库,在其中,数据是有组织的存储的;数据库管理系统(Database Management System,DBMS)是操纵和管理数据库的大型软件;SQL(Structured Query Language)则是操作关系型数据库的编程语言,定义了一套操作关系型数据库的统一标准。目前主流的关系型数据库管理系统可以从[DB-ENGINES](https://db-engines.com/en/ranking)查询到,22年6月份的情况如下:
|
||
|
||

|
||
|
||
无论是Oracle还是MySQL,无论是国外的还是国内各种数据库,只要是关系型数据库,我们都可以通过SQL语言去操作它。关系型数据库指的是数据建立在关系模型的基础上,由多张相互连接的二维表组成的,其特点是:
|
||
|
||
- 使用表结构存储数据,格式统一,便于维护
|
||
- 使用SQL语言进行操作,标准统一,使用方便
|
||
|
||
> **非关系型数据库:不通过表结构存储数据的数据库**
|
||
|
||
SQL是一种编程语言,只不过得益于设计,语法相对简单和智能,和其他编程语言一样,SQL也有其通用的语法规则:
|
||
|
||
1. SQL语句可以单行或者多行书写,以分号结尾
|
||
2. SQL语句可以通过空格/缩进来增强语句的可读性
|
||
3. MySQL数据库中的SQL语句不区分大小写,关键字建议大写
|
||
4. 注释又分为如下
|
||
- 单行注释:-- 注释内容,或者,# 注释内容(MySQL特有)
|
||
- 多行注释:/\*注释内容\*/
|
||
|
||
## 二、数据定义语言 -- DDL -- Data Defination Language
|
||
|
||
DDL是数据定义语言,用来定义(新建,删除和修改)数据库对象,比如数据库,表,字段等。
|
||
|
||
```sql
|
||
-- ############### 数据库相关 ###############
|
||
-- 创建数据库
|
||
CREATE DATABASE [IF EXISTS] db_name [DEFAULT CHARSET charset] [COLLATE seqReg];
|
||
|
||
-- 删除数据库
|
||
DROP DATABASE [IF EXISTS] db_name;
|
||
|
||
-- 切换使用数据库
|
||
USE db_name;
|
||
|
||
-- 目前MySQL不支持直接修改数据库名称,但是可以通过备份恢复,或者将旧数据库的表移动到新数据库中实现
|
||
CREATE DATABASE New_db;
|
||
mysqldump -uroot -p123456 Old_db > /tmp/old_db.sql;
|
||
mysql -uroot -p123456 new_db < /tmp/old_db.sql
|
||
-- -----------
|
||
CREATE DATABASE New_db;
|
||
RENAME TABLE Old_db.tb TO New_db.tb;
|
||
...
|
||
DROP DATABASE Old_db;
|
||
|
||
-- ############### 表相关 ###############
|
||
-- 创建表结构
|
||
CREATE TABLE tb_name(
|
||
column-1 datatype constraint [COMMENT "comment for column-1"],
|
||
column-2 datatype constraint [COMMENT "comment for column-2"],
|
||
......
|
||
column-n datatype constraint [COMMENT "comment for column-n"]
|
||
)[COMMENT "comment for tb_name"];
|
||
|
||
-- 添加表的字段和约束
|
||
ALTER TABLE tb_name ADD column datatype [constraint] [COMMENT comment];
|
||
|
||
-- 删除表的字段
|
||
ALTER TABLE tb_name DROP column;
|
||
|
||
-- 修改字段数据类型,默认不会修改约束
|
||
ALTER TABLE tb_name MODIFY COLUMN column datatype [constraint] [COMMENT comment];
|
||
|
||
-- 修改表的字段名,类型以及约束,默认不会修改约束
|
||
ALTER TABLE tb_name CHANGE old_column new_column new_datatype [constraint] [COMMENT comment];
|
||
|
||
-- 添加约束
|
||
ALTER TABLE tb_name ADD [CONSTRAINT cons_name] PRIMARY KEY (column);
|
||
ALTER TABLE tb_name-1 ADD [CONSTRAINT cons_name] FOREIGN KEY (column-1) REFERENCES tb_name-2 (column-2);
|
||
ALTER TABLE tb_name ADD [CONSTRAINT cons_name] UNIQUE KEY (column);
|
||
|
||
-- 删除约束,当唯一约束没有约束名的时候,可以通过`SHOW CREATE TABLE tb_name;`来查看名称
|
||
ALTER TABLE tb_name DROP PRIMARY KEY;
|
||
ALTER TABLE tb_name DROP CONSTRAINT cons_name;
|
||
|
||
|
||
-- 修改表的名称
|
||
ALTER TABLE old_tb_name RENAME TO new_tb_name;
|
||
|
||
-- 删除表,TRUNCATE方法是删除后重新创建该表,两种方法都会丢失数据
|
||
DROP TABLE [IF EXISTS] tb_name;
|
||
TRUNCATE TABLE tb_name;
|
||
```
|
||
|
||
## 三、数据操作语言 -- DML -- Data Manipulation Language
|
||
|
||
DML是数据操作语言,用来对数据库表中的数据记录进行增(INSERT)删(DELETE)改(UPDATE),这几个操作还是比较简单的,但是也比较危险,一定要注意条件的设定!!!
|
||
|
||
```sql
|
||
-- 添加表的一个记录(行),可以是指定字段赋值,也可以是全部字段赋值,没有指定值的字段取默认值
|
||
INSERT INTO tb_name (column-1, column-2) VALUES (value-1,value-2);
|
||
INSERT INTO tb_name VALUES (value-1,value-2,..., value-n);
|
||
INSERT INTO tb_name (column-1,column-2) VALUES (value-1,value-2), (value-1,value-2);
|
||
INSERT INTO tb_name VALUES (value-1,value-2,..., value-n), (value-1,value-2,..., value-n);
|
||
|
||
-- 修改表的记录(行),当不指定WHERE的时候,会修改整张表对的字段值
|
||
UPDATE tb_name SET column-1 = value-1, column-2 = value-2, ... [WHERE condition];
|
||
|
||
-- 删除表的记录,WHERE不指定的话则会删除整张表的数据
|
||
DELETE FROM tb_name [WHERE condition];
|
||
```
|
||
|
||
## 四、数据查询语言 -- DQL -- Data Query Language ★
|
||
|
||
DQL是数据查询语言,用来查询数据库表中的各种数据,也是日常使用最多的SQL类型。如实是先对查询语句的整理做了一个优先级的排序,然后根据不同的关键字做了实例拆分。
|
||
|
||
```sql
|
||
-- SELECT
|
||
-- 字段列表 ---------- 第四步执行
|
||
-- FROM
|
||
-- 表名列表 ---------- 第一步执行
|
||
-- WHERE
|
||
-- 条件列表 ---------- 第二步执行
|
||
-- GROUP BY
|
||
-- 分组字段列表 ------ 第三步执行(包括HAVING)
|
||
-- HAVING
|
||
-- 分组后条件列表
|
||
-- ORDER BY
|
||
-- 排序字段列表 ------ 第五步执行
|
||
-- LIMIT
|
||
-- 分页参数 ---------- 第六步执行
|
||
|
||
|
||
-- ############### 拆分实例--SELECT ###############
|
||
SELECT column-1, column-2... FROM tb_name;
|
||
SELECT column-1 [AS alias], column-2 [AS alias]... FROM tb_name;
|
||
SELECT DISTINCT column_name FROM tb_name;
|
||
|
||
-- ############### 拆分实例--WHERE ###############
|
||
SELECT column_name FROM tb_name WHERE condition;
|
||
|
||
-- ############### 拆分实例--聚合函数 ###############
|
||
-- 聚合函数都是作用在表中的某一字段(列),NULL值不参与计算
|
||
SELECT COUNT(*) FROM tb_name; /*记录(行)数量*/
|
||
SELECT AVG(age) FROM tb_name; /*求平均*/
|
||
SELECT MAX(age) FROM tb_name; /*求最大值*/
|
||
SELECT MIN(age) FROM tb_name; /*求最小值*/
|
||
SELECT SUM(age) FROM tb_name WHERE condition; /*条件求和*/
|
||
|
||
-- ############### 拆分实例--GROUP BY ###############
|
||
-- 需要注意的是WHERE是分组前过滤,HAVING是分组之后过滤
|
||
SELECT column_name FROM tb_name [WHERE condition] GROUP BY column_name [HAVING condition]
|
||
|
||
-- ############### 拆分实例--ORDER BY ###############
|
||
-- 排序方式有两种:ASC升序和DESC降序,字段1相同则按照字段2排序
|
||
SELECT column_name FROM tb_name ORDER BY column_name1 method-1, column_name2 method-2, ...
|
||
|
||
-- ############### 拆分实例--LIMIT ###############
|
||
SELECT column_name FROM tb_name LIMIT start, num_of_page;
|
||
-- 起始索引从0开始计数,起始索引=(页码数-1)*页面记录数
|
||
-- 分页查询是数据库的方言,不同数据库有不同的实现,MySQL是LIMIT
|
||
-- 如果分页查询的是第一页的数据,起始索引可以省略,简写为LIMIT 10
|
||
```
|
||
|
||
## 五、数据控制语言 -- DCL -- Data Control Language
|
||
|
||
DCL数据控制语言,用来创建管理数据库用户,管理控制数据库用户的访问权限。
|
||
|
||
```sql
|
||
-- ############### 创建管理用户 ###############
|
||
-- 查询所有用户,所有用户都存在与mysql这个数据库中!!!★
|
||
USE mysql
|
||
SELECT * FROM user;
|
||
-- 创建用户
|
||
CREATE USER 'username'@'hostname' IDENTIFIED BY 'PASSWD';
|
||
-- 修改用户密码
|
||
ALTER USER 'username'@'hostname' IDENTIFIED WITH mysql_native_password BY 'NEW PASSWD';
|
||
-- 删除用户
|
||
DROP USER 'username'@'hostname';
|
||
|
||
-- ############### 权限控制 ###############
|
||
-- 查询权限
|
||
SHOW GRANTS FOR 'username'@'hostname';
|
||
|
||
-- 授予权限
|
||
GRANT ALL PRIVILEGES ON db_name.tb_name TO 'username'@'hostname';
|
||
GRANT SELECT, UPDATE ON db_name.tb_name TO 'username'@'hostname';
|
||
|
||
-- 撤销权限
|
||
REVOKE priv_lists ON db_name.tb_name FROM 'username'@'hostname';
|
||
|
||
-- 权限刷新
|
||
FLUSH PRIVILEGES;
|
||
```
|
||
|
||
|**权限**|**说明**|
|
||
|:-|:-|
|
||
|ALL, ALL PRIVILEGES|完全权限,所有权限|
|
||
|SELECT|查询数据权限|
|
||
|INSERT|新增插入数据的权限|
|
||
|UPDATE|修改数据的权限|
|
||
|DELETE|删除数据的权限|
|
||
|ALTER|修改数据库表,或者用户信息的权限|
|
||
|DROP|删除数据库或者用户的权限|
|
||
|CREATE|创建数据库或者表的权限|
|
||
|
||
|
||
## 六、函数
|
||
|
||
MySQL 函数会对传递进来的参数进行处理,并返回一个处理结果,也就是返回一个值。MySQL 包含了一些常用的函数,剩余的可以到[「MySQL 官网」](https://www.mysql.com/)查询。可以对 MySQL 常用函数进行简单的分类,大概包括聚合函数、字符串型函数、数值型函数、日期时间函数以及流程控制类函数等。
|
||
|
||
#### 1. 聚合函数
|
||
|
||
|**函数**|**功能**|
|
||
|:-|:-|
|
||
|MIN|查询指定列的最小值|
|
||
|MAX|查询指定列的最大值|
|
||
|AVG|求平均值,返回指定列数据的平均值|
|
||
|COUNT|统计查询结果的行数|
|
||
|SUM|求和,返回指定列的总和|
|
||
|
||
#### 2. 字符串函数
|
||
|
||
|**函数**|**功能**|
|
||
|:-|:-|
|
||
|concat|将两个或多个字符串组合成一个字符串|
|
||
|length|以**字节**获取字符串的长度|
|
||
|char_length|以**字符**获取字符串的长度|
|
||
|left|获取指定长度的字符串的**左**边部分|
|
||
|right|获取指定长度的字符串的**右**边部分|
|
||
|replace|搜索并替换字符串中的子字符串|
|
||
|substring|从具有特定长度的位置开始提取一个子字符串|
|
||
|trim|从字符串中删除多余的指定字符,可以根据参数指定左右两端,以及字符信息|
|
||
|ltrim|从字符串**左**边删除多余的指定字符,可以根据参数指定字符信息|
|
||
|rtrim|从字符串**右**边删除多余的指定字符,可以根据参数指定字符信息|
|
||
|format|格式化具有特定区域设置的数字,舍入到小数位数|
|
||
|upper|将字符串内容转换成全部大写|
|
||
|lower|将字符串内容转换成全部小写|
|
||
|soundex|在WHERE条件中,根据发音规则来匹配选项|
|
||
|
||
#### 3. 数值计算函数
|
||
|
||
|**函数**|**功能**|
|
||
|:-|:-|
|
||
|abs|取绝对值|
|
||
|ceil|向上取整|
|
||
|div|整除运算|
|
||
|floor|向下取整|
|
||
|greatest|返回列表中最大值|
|
||
|least|返回列表中最小值|
|
||
|mod|取模运算|
|
||
|pi|返回π的值|
|
||
|pow|返回x的y次方|
|
||
|rand|返回0-1之间的随机数|
|
||
|round|四舍五入取整|
|
||
|sqrt|计算平方根|
|
||
|truncate|返回数值x保留到小数点后y位的值,与ROUND最大的区别是不会进行四舍五入|
|
||
|
||
#### 4. 日期时间类函数
|
||
|
||
|**函数**|**功能**|
|
||
|:-|:-|
|
||
|curdate|返回当前日期|
|
||
|sysdate|返回当前日期|
|
||
|datediff|计算两个DATE值之间的天数|
|
||
|timediff|计算两个TIME或DATETIME值之间的差值|
|
||
|timestampdiff|计算两个TIME或DATETIME值之间的差值|
|
||
|week|返回一个日期的星期数值|
|
||
|weekday| 返回一个日期表示为工作日/星期几的索引|
|
||
|dayofweek|返回日期的工作日索引|
|
||
|extract|提取日期的一部分|
|
||
|day|获取指定日期月份的天(日)|
|
||
|month|返回一个表示指定日期的月份的整数|
|
||
|year|返回日期值的年份部分|
|
||
|now|返回当前日期和时间|
|
||
|date_add|将时间值添加到日期值|
|
||
|date_sub|从日期值中减去时间值|
|
||
|date_format|根据指定的日期格式格式化日期值|
|
||
|dayame|获取指定日期的工作日的名称|
|
||
|str_to_date|将字符串转换为基于指定格式的日期和时间值|
|
||
|
||
#### 5. 流程控制类函数
|
||
|
||
|**函数**|**功能**|
|
||
|:-|:-|
|
||
|case|如果满足WHEN分支中的条件,则返回THEN分支中的相应结果,否则返回ELSE分支中的结果|
|
||
|if|根据给定的条件返回一个值|
|
||
|ifnull|如果第一个参数不为NULL,则返回第一个参数,否则返回第二个参数|
|
||
|nullif|如果第一个参数等于第二个参数,则返回NULL,否则返回第一个参数|
|
||
|
||
|
||
## 七、约束
|
||
|
||
在MySQL中,约束是指对表中数据的一种约束,能够帮助数据库管理员更好地管理数据库,并且能够确保数据库中数据的正确性和有效性。例如,在数据表中存放年龄的值时,如果存入200、300这些无效的值就毫无意义了。因此,使用约束来限定表中的数据范围是很有必要的。MySQL主要支持如下几种约束:
|
||
|
||
1. 主键约束
|
||
2. 外键约束
|
||
3. 唯一约束
|
||
4. 检查约束
|
||
5. 非空约束
|
||
6. 默认值约束
|
||
|
||
这些约束可以在创建表的时候添加,也可以在创建完成之后修改,建议后者。另外,在修改完表约束之后,需要再次修改表约束的时候,需要注意,需要一次性指定所有的约束,而不能一个个指定,因为每次修改表约束,实际上是在重写覆盖。
|
||
|
||
```sql
|
||
-- 创建表结构时,指定约束类型
|
||
CREATE TABLE Infos (
|
||
`id` int NOT NULL AUTO_INCREMENT,
|
||
`name` varchar(30) NOT NULL,
|
||
`age` tinyint NOT NULL,
|
||
`gender` char(6) NOT NULL DEFAULT 'MALE',
|
||
`city` varchar(30) NULL,
|
||
`addr` varchar(90) NOT NULL,
|
||
PRIMARY KEY(id),
|
||
FOREIGN KEY(city) REFERENCES Workers(city),
|
||
CHECK(age < 120),
|
||
UNIQUE KEY(name, addr)
|
||
)COMMENT infos of students;
|
||
|
||
-- 创建表结构后,修改字段约束类型
|
||
-- 可以参考ALTER的语法,完全相同
|
||
|
||
```
|
||
|
||
## 八、多表查询
|
||
|
||
**TBD. About in October, this part will be completed**
|
||
|
||
联结 组合
|
||
|
||
|
||
## 九、事务
|
||
|
||
**TBD. About in October, this part will be completed**
|
||
|
||
## 十、其他补充
|
||
|
||
> **1. 数据类型**
|
||
|
||
MySQL支持的数据类型很多,最常用的主要分为三类:数值类型,字符串类型以及日期时间类型,汇总如下
|
||
|
||
|数值类型|大小|描述|
|
||
|:-|:-|
|
||
|TINYINT|1 byte|(-128, 127)或(0, 255)|
|
||
|SMALLINT|2 bytes|(-32768, 32767)或(0, 65535)|
|
||
|MEDIUMINT|3 bytes|(-8388608, 8388607)或(0, 16777215)|
|
||
|INT|4 bytes|(-2147483648, 2147483647)或(0, 4294967295)|
|
||
|BIGINT|8 bytes|(-2^63, 2^63-1)或(0, 2^64-1)|
|
||
|FLOAT|4 bytes|(-3.4E+38, 3.4E+38)或(0, 1.75E-38~3.4E+38)|
|
||
|DOUBLE|8 bytes|(-1.8E+308, 1.8E+308)或(0, 2.2E-308~1.8E+308)|
|
||
|DECIMAL|M精度,D标度|当使用小数的时候,M表示整体位数,D表示小数位数|
|
||
|**字符串类型**|**大小**|**描述**|
|
||
|CHAR|0~255 bytes|定长字符串|
|
||
|VARCHAR|0~65535 bytes|不定长字符串|
|
||
|TINYBLOB|0~255 bytes|小型二进制形式的数据|
|
||
|TINYTEXT|0~255 bytes|小型文本类型数据|
|
||
|BLOB|0~65535 bytes|二进制形式的数据|
|
||
|TEXT|0~65535 bytes|文本类型数据|
|
||
|MEDIUMBLOB|0~16777215 bytes|中等规模二进制形式的数据|
|
||
|MEDIUMTEXT|0~16777215 bytes|中等规模文本类型数据|
|
||
|LONGBLOB|0~4294967295 bytes|极大规模二进制形式的数据|
|
||
|LONGTEXT|0~4294967295 bytes|极大规模文本类型数据|
|
||
|**时间类型**|**大小**|**格式**|
|
||
|DATE|3 bytes|YYYY-MM-DD|
|
||
|TIME|3 bytes|HH:MM:SS|
|
||
|YEAR|1 byte|YYYY|
|
||
|DATETIME|8 bytes|YYYY-MM-DD HH:MM:SS|
|
||
|TIMESTAMP|4 bytes|YYYY-MM-DD HH:MM:SS|
|
||
|
||
数字类型可以使用`UNSIGNED`或者`SIGNED`修饰符,表示有符号或者无符号;定长字符串指的是固定长度,比如`char(10)`和`varchar(10)`同时存储"hello"的时候,前者还是使用10个字符,而后者只会使用5个字符空间,另外在MySQL中,汉字也是只占用1个字符的;时间类型的DATETIME和TIMESTAMP的范围不同,后者只能到2038年。
|
||
|
||
> **2. 运算符**
|
||
|
||
|**比较运算符**|**功能**|
|
||
|:-|:-|
|
||
|\>|判断大于|
|
||
|\>=|判断大于等于|
|
||
|\<|判断小于|
|
||
|\<=|判断小于等于|
|
||
|=|判断等于|
|
||
|\<\>或者!=|判断不等于|
|
||
|BETWEEN...AND...|在某个闭区间范围内选择|
|
||
|IN(...)|选择IN之后的列表当中的一个|
|
||
|LIKE 占位符|模糊匹配,_匹配单个字符,%匹配任一个字符|
|
||
|IS NULL|是NULL|
|
||
|**逻辑运算符**|**功能**|
|
||
|AND或者&&|与,多个条件同时成立|
|
||
|OR或者\|\||或者,多个条件任意成立一个|
|
||
|NOT或者!|非,不是|
|
||
|
||
> **3. WHERE VS HAVING**
|
||
|
||
WHERE和HAVING都是条件过滤,其执行顺序是WHERE最先执行,聚合函数其次,最后是HAVING,但是也有区别:
|
||
|
||
- 执行时机不同:WHERE是分组之前过滤,HAVING是分组之后过滤
|
||
- 判断条件不同:WHERE不能对聚合函数做判断,而HAVING可以
|
||
- 分组之后SELECT查询的一般是分组字段或者聚合函数,查询其他字段无意义
|
||
|
||
> **4. 备份与恢复**
|
||
|
||
对于日常非生产环境,备份恢复还是挺随意的,使用`mysqldump`和`mysql`命令就可以了,SQL的备份方式还是很有讲究的,如下方式可能不适用于生产环境,但对于个人用户感觉是足够了。需要注意的是,无论使用哪种方法去备份,一定要备份sys库,因为这里面存储了用户信息,如果了解是具体哪几个表,也可以只备份那几个表。
|
||
|
||
```sql
|
||
-- 备份方法-1
|
||
mysql -e "show databases;" -u root | grep -Ev "Database|information_schema|performance_schema" | xargs mysqldump --skip-lock-tables -uroot --databases | gzip > backups.sql
|
||
|
||
-- 备份方法-2
|
||
mysqldump --skip-lock-tables -uroot --databases 数据库名 > backups.sql
|
||
|
||
-- 恢复方法
|
||
mysql -u root -p passwd < backups.sql
|
||
```
|
||
|
||
> **5. 书写规则**
|
||
|
||
通常情况下SQL语句不区分大小写,因此SELECT和select是相同的,甚至SeLect也是可以起作用,但是为了规范书写以及让所写的代码更有可读性和可维护性,一般建议使用如下规则:
|
||
|
||
- 关键字:一般全部大写
|
||
- 数据库名:一般全部大写,使用一个单词或者多个单词以下划线连接组合
|
||
- 表名:一般首字母大写,使用一个单词或者多个单词以下划线连接组合
|
||
- 字段名:一般小写,使用一个单词或者多个单词以下划线连接组合
|
||
- 值:一般小写,看情况使用,无特殊规定
|
||
- 注释:大小写混用,看情况使用
|
||
|
||
> **6. 通配符**
|
||
|
||
通配符一般用在WHERE子语句中做条件过滤,类似于各种语言中的正则表达式或者Bash中的通配符的概念。MySQL中的通配符是比较简单,相关的符号有如下几种:
|
||
|
||
- %: 任意字符出现任意次数,除了NULL
|
||
- \_: 匹配单个字符,除了NULL
|
||
- []: 指定一个字符集,必须匹配指定位置的一个字符
|
||
- ^: 在方括号内开头位置表示取补集
|
||
|
||
|
||
|
||
|
||
## 【END】参考文档
|
||
|
||
- [SQL必知必会 5th Edition(强烈推荐!!!)](https://forta.com/books/0135182794/)
|
||
- [黑马程序员 MySQL数据库入门到精通](https://www.bilibili.com/video/BV1Kr4y1i7ru)
|
||
- [MySQL常用函数](https://www.yiibai.com/mysql/functions.html)
|
||
|
||
|