MySQL基础
1.MySQL下载安装(Windows)
1.1MySQL下载
官网:https://dev.mysql.com/downloads/mysql/
1.2MySQL安装
-
解压zip文件,重命名文件夹为MySQL。
-
将
D:\MySQL\bin
设置为系统环境变量 -
初始化数据库:
mysqld --initialize-insecure
,会在MySQL目录生成data
文件夹。 -
为Windows系统安装MySQL服务 :命令:
mysqld install
作用:为Windows系统安装MySQL服务,默认服务名为:mysql (以管理员身份运行Windows PowerShell) -
启动MySQL,
net start mysql
,输入mysql -u root
.
2.MySQL基础
2.1MySQL相关概念
MySQL 为关系型数据库 (Relational Database Management System), 这种所谓的 “关系型” 可以理解为 “表格” 的概念, 一个关系型数据库由一个或数个表格组成, 如图所示的一个表格:
- 表头 (header): 每一列的名称;
- 列 (row): 具有相同数据类型的数据的集合;
- 行 (col): 每一行用来描述某个人 / 物的具体信息;
- 值 (value): 行的具体信息, 每个值必须与该列的数据类型相同;
- 键 (key): 表中用来识别某个特定的人 \ 物的方法, 键的值在当前列中具有唯一性。
2.2MySQL 脚本基本组成
与常规的脚本语言类似, MySQL 也具有一套对字符、单词以及特殊符号的使用规定, MySQL 通过执行 SQL 脚本来完成对数据库的操作, 该脚本由一条或多条 MySQL 语句 (SQL 语句 + 扩展语句) 组成, 保存时脚本文件后缀名一般为 .sql
。在控制台
下, MySQL 客户端也可以对语句进行单句
的执行而不用保存为. sql 文件。
标识符
标识符用来命名一些对象
, 如数据库、表、列、变量
等, 以便在脚本中的其他地方引用。MySQL 标识符命名规则稍微有点繁琐, 这里我们使用万能命名规则: 标识符由字母、数字或下划线 (_)
组成, 且第一个字符必须是字母或下划线
。
对于标识符是否区分大小
写取决于当前的操作系统
, Windows
下是不
敏感的, 但对于大多数 linux\unix
系统来说, 这些标识符大小写是敏感
的。
关键字
MySQL 的关键字众多, 这里不一一列出, 在学习中学习。这些关键字有自己特定的含义, 尽量避免作为标识符。
语句
MySQL 语句
是组成 MySQL 脚本的基本单位, 每条语句能完成特定的操作, 他是由 SQL 标准语句 + MySQL 扩展语句
组成。
函数
MySQL 函数用来实现数据库操作的一些高级功能, 这些函数大致分为以下几类: 字符串函数、数学函数、日期时间函数、搜索函数、加密函数、信息函数
。
2.3MySQL 中的数据类型
MySQL 有三大类数据类型, 分别为数字、日期 \ 时间、字符串, 这三大类中又更细致的划分了许多子类型
数字类型
- 整数: tinyint、smallint、mediumint、int、bigint
- 浮点数: float、double、real、decimal
日期和时间: date、time、datetime、timestamp、year
字符串类型
- 字符串: char、varchar
- 文本: tinytext、text、mediumtext、longtext
- 二进制 (可用来存储图片、音乐等): tinyblob、blob、mediumblob、longblob
-
2.3.1整型
-
MySQL 数据类型 含义(有符号) tinyint(m) 1 个字节 范围 (-128~127) smallint(m) 2 个字节 范围 (-32768~32767) mediumint(m) 3 个字节 范围 (-8388608~8388607) int(m) 4 个字节 范围 (-2147483648~2147483647) bigint(m) 8 个字节 范围 (±9.22*10 的 18 次方) -
取值范围如果加了
unsigned
,则最大值翻倍
,如 tinyint unsigned 的取值范围为 (0~256)。
int(m) 里的m
是表示SELECT 查询结果集
中的显示宽度
,并不影响
实际的取值范围
,没有影响到显示的宽度,不知道这个 m 有什么用。 -
“(M)”指定了 int 型数值显示的宽度,如果字段数据类型是 int(4),则:当显示数值 10 时,在左边要补上 “00”;当显示数值 100 是,在左边要补上“0”;当显示数值 1000000 时,已经超过了指定宽度“(4)”,因此按原样输出。 在使用 MySQL 数据类型中的整数类型(tinyint, smallint, mediumint, int/integer, bigint)时,非特殊需求下,在数据类型后加个“(M)”,我想不出有何意义。https://blog.csdn.net/zh521zh/article/details/50605737
-
2.3.2浮点型 (float 和 double)
-
MySQL 数据类型 含义 float(m,d) 单精度浮点型 8 位精度 (4 字节) m 总个数,d 小数位 double(m,d) 双精度浮点型 16 位精度 (8 字节) m 总个数,d 小数位 -
设一个字段定义为 float(5,3),如果插入一个数 123.45678, 实际数据库里存的是 123.457,但总个数还以实际为准,即 6 位。
-
2.3.3定点数
-
浮点型在数据库中存放的是近似值,而
定点类型
在数据库中存放的是精确值
。
decimal(m,d) 参数 m<65 是总个数
,d<30 且 d<m 是小数位
。 -
2.3.4字符串 (char,varchar,_text)
-
MySQL 数据类型 含义 char(n) 固定长度,最多 255 个字符 varchar(n) 固定长度,最多 65535 个字符 tinytext 可变长度,最多 255 个字符 text 可变长度,最多 65535 个字符 mediumtext 可变长度,最多 2 的 24 次方 - 1 个字符 longtext 可变长度,最多 2 的 32 次方 - 1 个字符 -
char 和 varchar:
-
char(n) 若存入字符数
小于 n
,则以空格
补于其后
,查询
之时再将空格去掉
。所以char
类型存储的字符串末尾不能有空格
,varchar
不限于此。 -
char(n) 固定长度,char(4) 不管是存入几个字符,都将占用
4
个字节,varchar 是存入的实际字符数 + 1 个字节
(n<=255)或2 个字节
(n>255),所以 varchar(4), 存入 3 个字符将占用 4 个字节。 -
char 类型的字符串检索速度要比 varchar 类型的
快
。 -
varchar 和 text:
-
varchar 可指定 n,text 不能指定,内部存储 varchar 是存入的实际字符数 + 1 个字节(n<=255)或 2 个字节 (n>255),text 是
实际字符数 + 2 个字节
。 -
text 类型
不能有默认值
。 -
varchar 可直接创建索引,text 创建索引要指定前多少个字符。varchar 查询速度
快
于 text, 在都创建索引的情况下,text 的索引似乎不起作用。 -
2.3.5二进制数据 (_Blob)
-
- _BLOB 和 _text 存储方式不同,
_TEXT
以文本
方式存储,英文存储区分大小写
,而_Blob
是以二进制
方式存储,不分大小写
。 - _BLOB 存储的数据只能
整体读出
。 - _TEXT 可以指定字符集, _BLO 不用指定字符集。
- _BLOB 和 _text 存储方式不同,
-
2.3.6日期时间类型
-
MySQL 数据类型 含义 date 日期 ‘2008-12-2’ time 时间 ‘12:25:36’ datetime 日期时间 ‘2008-12-2 22:06:44’ timestamp 自动存储记录修改时间 -
若定义一个字段为
timestamp
,这个字段里的时间数据会随其他字段修改的时候自动刷新,所以这个数据类型的字段可以存放这条记录最后被修改的时间
。 -
2.3.7数据类型的属性
-
MySQL 关键字 含义 NULL 数据列可包含 NULL 值 NOT NULL 数据列不允许包含 NULL 值 DEFAULT 默认值 PRIMARY KEY 主键 AUTO_INCREMENT 自动递增,适用于整数类型 UNSIGNED 无符号 CHARACTER SET name 指定一个字符集
2.4连接数据库
当 MySQL 服务已经运行
时, 我们可以通过 MySQL 自带的客户端工具登录到 MySQL 数据库中, 首先打开命令提示符, 输入以下格式的命名:
mysql -h 主机名 -u 用户名 -p
- -h : 该命令用于指定客户端所要登录的 MySQL 主机名, 登录当前机器该参数可以省略;
- -u : 所要登录的用户名;
- -p : 告诉服务器将会使用一个密码来登录, 如果所要登录的用户名密码为空, 可以忽略此选项。
以登录刚刚安装在本机的 MySQL 数据库为例, 在命令行下输入 mysql -u root -p
按回车确认, 如果安装正确且 MySQL 正在运行, 会得到以下响应:
Enter password:
若密码存在, 输入密码登录, 不存在则直接按回车登录, 按照本文中的安装方法, 默认 root
账号是无密码的。登录成功后你将会看到 Welecome to the MySQL monitor...
的提示语。
然后命令提示符会一直以 mysql>
加一个闪烁的光标等待命令的输入, 输入 exit
或 quit
退出登录。
2.5修改 root 用户密码
按照本文的安装方式, root 用户默认是没有密码的, 重设 root 密码的方式也较多, 这里仅介绍一种较常用的方式。使用 mysqladmin 方式:
打开命令提示符界面, 执行命令:
mysqladmin -u root -p password 新密码
执行后提示输入旧密码完成密码修改, 当旧密码为空时直接按回车键确认即可。
2.6选择所要操作的数据库
要对一个数据库进行操作, 必须先选择该数据库, 否则会提示错误:
ERROR 1046\(3D000\): No database selected
两种方式对数据库进行使用的选择:
一: 在登录数据库时指定, 命令: mysql -D 所选择的数据库名 -h 主机名 -u 用户名 -p
例如登录时选择刚刚创建的数据库: mysql -D samp_db -u root -p
二: 在登录后使用 use
语句指定, 命令: use 数据库名;
use
语句可以不加分号, 执行use samp_db
来选择刚刚创建的数据库, 选择成功后会提示: Database changed
2.7SQL 命令的类型
2.7.1DDL (Data Definition Language) 数据定义语言
数据定义语言 (Data Definition Language, DDL) 是 SQL 语言集中,负责数据结构定义与数据库对象定义的语言,它主要包括三个关键字:create ,alter , drop(数据库关键字不分大小写 ), 主要操作对象有数据库、表、索引、视图等.https://baike.baidu.com/item/DDL/21997
1.操作数据库
使用 create database
语句可完成对数据库的创建, 创建命令的格式如下:
-- 创建数据库
create database 数据库名 [其他选项];
-- 例如我们需要创建一个名为 samp_db 的数据库, 在命令行下执行以下命令:
create database samp_db character set gbk;
-- 使用数据库
use 数据库名称;
use samp_db;
-- 删除这个数据库
drop database 数据库名称;
drop samp_db;
为了便于在命令提示符下显示中文, 在创建时通过 character set gbk
将数据库字符编码指定为 gbk
。创建成功时会得到 Query OK, 1 row affected(0.02 sec)
的响应。
注意: MySQL 语句以分号(;)
作为语句的结束, 若在语句结尾不添加分号时, 命令提示符会以 ->
提示你继续输入 (有个别特例, 但加分号是一定不会错的);
提示: 可以使用 show databases
; 命令查看已经创建了哪些数据库。
2.操作表结构
2.1创建表
使用 create table
语句可完成对表的创建, create table
的常见形式:
create table 表名称(列声明);
/* 以创建 students 表为例, 表中将存放 学号(id)、姓名(name)、性别(sex)、年龄(age)、联系电话(tel) 这些内容: */
create table students
(
id int unsigned not null auto_increment primary key,
name char(8) not null,
sex char(4) not null,
age tinyint unsigned not null,
tel char(13) null default "-"
);
create table tablename(columns)
为创建数据库表的命令, 列的名称以及该列的数据类型将在括号内完成;
括号内声明了5列内容, id、name、sex、age、tel为每列的名称, 后面跟的是数据类型描述, 列与列的描述之间用逗号(,)
隔开;
以 "id int unsigned not null auto_increment primary key"
行进行介绍:
- “id” 为列的名称;
- “int” 指定该列的类型为 int(取值范围为 -8388608到8388607), 在后面我们又用 “unsigned” 加以修饰, 表示该类型为无符号型, 此时该列的取值范围为 0到16777215;
- “not null” 说明该列的值不能为空, 必须要填, 如果不指定该属性, 默认可为空;
- “auto_increment” 需在整数列中使用, 其作用是在插入数据时若该列为 NULL, MySQL将自动产生一个比现存值更大的唯一标识符值。在每张表中仅能有一个这样的值且所在列必须为索引列。
- “primary key” 表示该列是表的主键, 本列的值必须唯一, MySQL将自动索引该列。
下面的 char(8)
表示存储的字符长度为8, tinyint
的取值范围为 -127到128, default
属性指定当该列值为空时的默认值。
提示: 1. 使用 show tables
; 命令可查看已创建了表的名称; 2. 使用 describe 表名
; 命令可查看已创建的表的详细信息。
对于一些较长的语句在命令提示符下可能容易输错, 因此我们可以通过任何
文本编辑器
将语句输入好后保存为createtable.sql
的文件中, 通过命令提示符下的文件重定向执行执行该脚本。打开命令提示符, 输入:
mysql -D samp_db -u root -p < createtable.sql
(提示: 1.如果连接远程主机请加上
-h
指令; 2.createtable.sql
文件若不在当前工作目录下需指定文件的完整路径。)[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ryu54HlY-1649400613951)(https://gitee.com/peanuts-are-delicious/seriousnote/raw/master/Pics10/image-20220404221849370.png)]
2.2添加注释
为了让别人能清楚我们定义的字段的含义,我们需要给我们创建的字段添加对应的注释来说明。
CREATE TABLE T_USER(
id int(3) ,
user_name varchar(30) COMMENT '用户名'
)COMMENT='用户表'
ALTER TABLE t_user
MODIFY COLUMN user_name varchar(20) COMMENT '姓名' ;
2.3删除表
删除表通过DROP
关键字来实现
DROP TABLE T_USER;
2.4修改表
-- 添加字段
ALTER TABLE T_USER ADD address VARCHAR(2);
-- 修改字段类型
ALTER TABLE T_USER MODIFY address VARCHAR(50);
-- 修改字段名称
ALTER TABLE T_USER RENAME COLUMN address TO present_address;
-- 删除字段
ALTER TABLE T_USER DROP COLUMN present_address;
2.5表结构的约束
- 非空约束
ALTER TABLE T_USER
CHANGE id id INT NOT NULL COMMENT '主键';
-- 或者在建表的时候指定
# 删除表
DROP TABLE T_USER;
CREATE TABLE T_USER(
id INT(5) NOT NULL COMMENT '主键',
user_name VARCHAR(20) COMMENT '账号' ,
age INT(2) COMMENT '年龄' DEFAULT 18
)COMMENT='用户表' ;
- 默认值
DROP TABLE T_USER;
CREATE TABLE T_USER(
id INT(5) NOT NULL COMMENT '主键',
user_name VARCHAR(20) COMMENT '账号' ,
age INT(2) COMMENT '年龄' DEFAULT 18
)COMMENT='用户表' ;
- 唯一约束
-- 该字段中不能出现相同的值,null 除外
DROP TABLE T_USER;
CREATE TABLE T_USER(
id INT(5) UNIQUE COMMENT '主键',
user_name VARCHAR(20) COMMENT '账号' ,
age INT(2) COMMENT '年龄' DEFAULT 18
)COMMENT='用户表' ;
-- 建表后设置字段的唯一约束条件
ALTER TABLE t_user add CONSTRAINT unique_name UNIQUE(user_name);
alter table t_user add unique (user_name);
- 主键
-- 能唯一标识一条记录的字段,不能为空,唯一约束,只能有一个主键。
DROP TABLE T_USER;
CREATE TABLE T_USER(
id INT(5) PRIMARY KEY COMMENT '主键',
user_name VARCHAR(20) COMMENT '账号' ,
age INT(2) COMMENT '年龄' DEFAULT 18
)COMMENT='用户表' ;
-- 联合主键:多个字段组合的信息是不能出现重复的
ALTER TABLE t_user
ADD PRIMARY KEY (id, user_name);
- 外键
/*外键就是在主表中可以重复出现, 但是它的值是另一个表的主键, 外键使两个表相关,外键可约束表的数据的更新,外键和主键表联系,数据类型要统一,长度 (存储大小) 要统一,在更新数据的时候会保持一致性*/
-- 删除表
DROP TABLE T_USER;
CREATE TABLE T_USER(
id INT(5) PRIMARY KEY COMMENT '主键',
user_name VARCHAR(20) COMMENT '账号' ,
age INT(2) COMMENT '年龄' DEFAULT 18,
deptid INT(30) ,
CONSTRAINT FK_DEPT_ID FOREIGN KEY(deptid) REFERENCES T_DEPT(dept_id)
)COMMENT='用户表' ;
ALTER TABLE T_USER ADD
CONSTRAINT FK_DEPT_ID FOREIGN KEY(deptid) REFERENCES T_DEPT(dept_id)
/*注意:外键字段的级联关系,如果我们要删除外键对应的主键记录,那么必须要先删除该注解对应的所有的外键记录,否则删除不成功,
实际开发中我们对主键的使用比较少。*/
2.6Check
-- 粒度更细的约束。
DROP TABLE T_USER;
CREATE TABLE T_USER(
id INT(5) PRIMARY KEY COMMENT '主键',
user_name VARCHAR(20) COMMENT '账号' ,
age INT(3) COMMENT '年龄' ,
CHECK (age > 0 AND age < 40)
)COMMENT='用户表' ;
/*between and
in not in or*/
3.字段类型(参考2.3小节)
2.7.2DML (Data Manipulation Language) 数据操作语言
数据操纵语言(Data Manipulation Language, DML)是 SQL 语言中,负责对数据库对象运行数据访问工作的指令集,以 INSERT、UPDATE、DELETE 三种指令为核心,分别代表插入、更新与删除。https://baike.baidu.com/item/%E6%95%B0%E6%8D%AE%E6%93%8D%E4%BD%9C%E8%AF%AD%E8%A8%80
1.INSERT
insert 语句可以用来将一行或多行数据插到数据库表中, 使用的一般形式如下:
insert [into] 表名 [(列名1, 列名2, 列名3, ...)] values (值1, 值2, 值3, ...);
其中 []
内的内容是可选的, 例如, 要给 samp_db
数据库中的 students
表插入一条记录, 执行语句:
insert into students values(NULL, "Peanut", "Male", 24, "11012011922");
按回车键确认后若提示 Query Ok, 1 row affected (0.05 sec)
表示数据插入成功。若插入失败请检查是否已选择需要操作的数据库。
有时我们只需要插入部分数据, 或者不按照列的顺序进行插入, 可以使用这样的形式进行插入:
alter table students modify sex varchar(6)
insert into students (name, sex, age) values("Delicious", "Female", 21);
复制表结构和数据
create table student as select * from students;
复制表结构(不会复制字段的属性)
create table users as select * from students where 1 <> 1;
把其他表结构中的数据插入到表中:
insert into users(id,name,age) select id,name,age from students;
可以在单行插入的后面添加多个插入的信息列。
-- 插入语句后面可以跟多个插入的信息
insert into users (name,age)values('Cake',22),('Book',22),('He',22);
insert into students (name,age)values('Cake',22),('Book',22),('He',22);
2.UPDATE
update
语句可用来修改表中的数据, 基本的使用形式为:
update 表名称 set 列名称=新值 where 更新条件;
使用示例:
将 id 为 5 的手机号改为默认的 “-”:
update students set tel=default where id=5;
将所有人的年龄增加 1:
update students set age=age+1;
将手机号为 13288097888 的姓名改为 “张伟鹏”, 年龄改为 19:
update students set name="Peanut",
age=19 where tel="11012012022";
3.DELETE
delete
语句用于删除表中的数据, 基本用法为:
delete from 表名称 where 删除条件;
使用示例:
删除 id 为 2 的行:
delete from students where id=2;
# 如果不带where 条件 那么表示删除该表中的所有的记录 慎用!!! 删表跑路
delete from students ;
# delete insert update 语句都会走事务处理,也就是我们需要显示的commit和rollback;
删除所有年龄小于 21 岁的数据:
delete from students where age<20;
删除表中的所有数据:
delete from students;
truncate
删除
-- truncate 直接清空表结构中的所有的数据,效率高,但是不能回滚。
TRUNCATE TABLE t_user_1 # where 1 = 1;
2.7.3DQL (Data Query Language) 数据查询语言
数据查询语言(Data Query Language, DQL)是 SQL 语言中,负责进行数据查询而不会对数据本身进行修改的语句,这是最基本的 SQL 语句。保留字 SELECT 是 DQL(也是所有 SQL)用得最多的动词,其他 DQL 常用的保留字有 FROM,WHERE,GROUP BY,HAVING 和 ORDER BY。这些 DQL 保留字常与其他类型的 SQL 语句一起使用。
-- 语法
select -- 筛选列名称
from -- 确定表名称
where -- where后面的条件,进行行过滤,过滤掉不满足条件的行
group by -- 对列进行分组
having -- 行过滤
order by -- 排序
limit -- 返回限制的行数
创建一张表格
use test;
drop table if exists student;
create table student(
stuNumber int auto_increment primary key,
name varchar(50),
gender varchar(10),
age int,
major varchar(50)
)default charset=utf8;
insert into student values(default,'张三','男','20','计科');
insert into student values(default,'李四','女','19','土木');
insert into student values(default,'王五','男','19','数统');
insert into student values(default,'赵六','男','21','外院');
insert into student values(default,'萧炎','男','20','计科');
insert into student values(default,'李七夜','男','22','文院');
insert into student values(default,'安澜','女','22','体院');
insert into student values(default,'木婉清','女','20','土木');
1.查询所有数据
select * from student;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gGP9Cple-1649400613955)(https://gitee.com/peanuts-are-delicious/seriousnote/raw/master/Pics10/image-20220405232419601.png)]
2.查询指定的列
场景: 查询 student 表中的学号和名字
select
stuNumber,
name
from
student;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cUAetJ9b-1649400613964)(https://gitee.com/peanuts-are-delicious/seriousnote/raw/master/Pics10/image-20220405233826390.png)]
3.列别名
别名就是小名
使用别名的目的:让查询的结果更友好
列别名通常写在列名称的后面,列名称和列别名之间有一个空格
SELECT
stuNumber 学号,
name 姓名,
gender 性别,
age 年龄,
major 专业
FROM
student;
4.表别名
使用表别名目的:提高 DQL 的可读性,为后面学习多表联合查询做铺垫
表别名写在表名称的后面,表名称和表别名之间有一个空
SELECT
stuNumber 学号,
name 姓名,
gender 性别,
age 年龄,
major 专业
FROM
student 学生表;
5.DQL的算术运算符
MySQL只支持4种算数运算符。
MySQL的算数运算符可以跟列名称一起使用,通常对某一列数数据进行算术运算
场景: 把学生表的年龄都加1
-- 把学生表的年龄加1
SELECT
stuNumber,
`name`,
gender,
age + 1,
major
FROM
student;
6.DQL的比较运算符
> >= < <= !=和<> 都表示不等于
= 表示等于 ,MySQL没有 == 运算符比较运算符用在from之后,不能用在from之前,对条件进行过滤,过滤掉不满足条件的记录。
场景: 查询年龄大于20的学生
-- 查询年龄大于20的学生
SELECT
*
FROM
student
WHERE
age > 20;
执行顺序:from(确定要查询哪张表)—> where(过滤不满足的条件) -----> select(选择结果集中的列)
小结
:where必须写在from关键字的后面,作为from关键字的过滤条件
场景: 查询不是计科的所有学生的信息
-- 查询不是计科的所有学生的信息
SELECT
*
FROM
student
WHERE
major <> '计科';
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SN2aGjwW-1649400613966)(https://gitee.com/peanuts-are-delicious/seriousnote/raw/master/Pics10/image-20220405235509322.png)]
7.DQL的逻辑运算符
Java: && | | !
并且 或者 非
MySQL: and or not
场景: 查询专业为土木并且年龄为20的学生
-- 查询专业为土木并且年龄为20的学生
SELECT
*
FROM
student
WHERE
major = '土木'
AND age = '20';
场景: 查询专业为土木或者年龄为20的学生
-- 查询专业为土木或者年龄为20的学生
SELECT
*
FROM
student
WHERE
major = '土木'
OR age = '20';
场景: 查询专业为土木并且年龄不为20的学生
-- 查询专业为土木并且年龄不为20的学生
SELECT
*
FROM
student
WHERE
major = '土木'
AND NOT age = '20';
8.区间查询
between and 关键字 在…之间
场景: 查询年龄在18-20岁之间所有学生的信息
-- 查询年龄在18-20岁之间所有学生的信息
SELECT
*
FROM
student
WHERE
age BETWEEN 18
AND 20;
9.in集合查询
in 关键字 在…里面
场景: 查询专业是计科、文院、外院的所有学生的信息
-- 查询专业是计科、文院、外院的所有学生的信息
SELECT
*
FROM
student
WHERE
major IN ( '计科', '文院', '外院' );
10.like模糊查询
like 关键字 像…一样
语法:where 字段名称 like ‘要查找的字符串%’
%表示模糊匹配多个字符
要查找的字符串必须写在一对半角单引号里面
模糊查询有三种场景:前面精确后面模糊、前面模糊后面精确、先后模糊中间精确
输入法中全角半角的区别:所占字符大小不一样。半角输入法状态下字符仅占一个字节,可以理解成相当于半个汉字。而全角输入法状态下一个字符占两个字节,就是相当于一个汉字。
10.1前面精确后面模糊
场景: 查询所有姓李的学生信息
-- 查询所有姓李的学生信息
SELECT
*
FROM
student
WHERE
name LIKE '李%';
小结:like关键字通常用在where后面
like查询的数据类型通常是字符串
类型
10.2前面模糊后面精确
语法:where 字段名称 like ‘%要查找的字符串’
场景: 查询所有名字以三结尾的学生信息
-- 查询所有名字以三结尾的学生信息
SELECT
*
FROM
student
WHERE
`name` LIKE '%三';
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aAvUUyx9-1649400613970)(https://gitee.com/peanuts-are-delicious/seriousnote/raw/master/Pics10/image-20220406085757367.png)]
10.3前后模糊中间精确
语法:where 字段名称 like ‘%要查找的字符串%’
场景: 查询名字中带有安的学生信息
-- 查询名字中带有安的学生信息
SELECT
*
FROM
student
WHERE
NAME LIKE '%安%';
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H6N4bsId-1649400613970)(https://gitee.com/peanuts-are-delicious/seriousnote/raw/master/Pics10/image-20220406085858349.png)]
11.distinct过滤掉重复的行
场景: 查询所有学生的专业,不能重复
-- 查询所有学生的专业,不能重复
SELECT DISTINCT
major
FROM
student;
小结:distinct关键字表示过滤掉重复的行,后面跟列名称
12.聚合函数
MySQL支持5个聚合函数,用于对查询结果集做汇总
count(计数)、sum(求总和)、avg(求平均值)、max(计算最大值)、min(计算最小值)
特征:每个聚合函数查询结果只能是"单行单列"
列名称作为聚合函数的参数,参数类型最好使用数值类
12.1count
通常获取结果集总行数
场景: 查询student表中有多少行数据
-- 查询student表中有多少行数据
SELECT
count( stuNumber )
FROM
student;
12.2sum
计算某一列的和
场景: 查询所有学生年龄的总和
-- 查询所有学生年龄的总和
SELECT
sum( age )
FROM
student;
12.3max
计算某一列的最大值
场景: 查询学生表的最大年龄
-- 查询学生表的最大年龄
SELECT
max( age )
FROM
student;
12.4min
计算某一列的最小值
和max用法相同,不再赘述
12.5avg
计算某一列的平均值
场景: 查询所有学生的平均年龄
-- 查询所有学生的平均年龄
SELECT
avg( age )
FROM
student;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6dtG73AE-1649400613976)(https://gitee.com/peanuts-are-delicious/seriousnote/raw/master/Pics10/image-20220406090835995.png)]
13.group by分组和汇总查询
分组关键字: group by
group by 将表中的数据分成若干组
语法:
select 列名称,聚合函数
from 表
group by 列名称[列别名];
场景: 查询每个专业的年龄平均年龄
-- 查询每个专业的年龄总和
SELECT
major,
avg( age )
FROM
student
GROUP BY
major;
注意:如果一个select查询语句有where和group by,那么group by
必须写在where
的后面
场景: 查询每个专业的年龄总和,但不包括学号为5的学生
-- 查询每个专业的平均年龄,但不包括学号为5的学生
SELECT
major,
avg( age )
FROM
student
WHERE
stuNumber <> 5
GROUP BY
major;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dTaL40a9-1649400613977)(https://gitee.com/peanuts-are-delicious/seriousnote/raw/master/Pics10/image-20220406091345266.png)]
14.having
having跟where关键字一样都用于行过滤,但是where不支持聚合函数,如果对聚合函数进行过滤此时使用having关键字。
场景: 在上一个场景的基础上统计年龄大于20的年龄综合
-- 在上一个场景的基础上统计年龄大于20的年龄总和
SELECT
major,
sum( age )
FROM
student
WHERE
stuNumber <> 5
GROUP BY
major
HAVING
sum( age ) > 20;
15.order by 排序
排序关键字: order by
语法 : order by 列名称 或者 列别名 asc 或者 desc
asc 升序排序
desc 降序排序
场景: 在上一个场景的基础上对年龄总和进行降序排序
-- 在上一个场景的基础上对年龄总和进行降序排序
SELECT
major,
sum( age )
FROM
student
WHERE
stuNumber <> 5
GROUP BY
major
HAVING
sum( age ) > 20
ORDER BY
sum( age ) DESC;
16.limit返回最大限制的行数
关键字 limit
limit限制最多返回的行数,工作中通常用户分页查询
limit n; 此时n表示最多返回n表
limit m , n ; 此时m表示下标,n表示最多返回n条
场景: 查询第三行后面三行的学生信息
-- 查询第三行后面三行的学生信息
SELECT
*
FROM
student
LIMIT 3,
3;
17.多表联合查询
将多个表数据合并成一张表(内存表),简称:化零为整。常用的多表联合查询:内连接(inner join)、左外连接(left join)、右外连接(right join)、自连接、全连接(union union all)。
17.1 内连接
A∩B:A表与B表的交集
关键字 inner join on
inner join查询多张表条件都满足的数据(A表和B表的交集)
on 条件过滤,过滤掉不满足条件的语
此时再创建一个院系表
drop table if exists departments;
create table departments(
id int auto_increment primary key,
major varchar(50)
)default charset=utf8;
插入若干条记录
insert into departments values(default,'计科');
insert into departments values(default,'土木');
insert into departments values(default,'数统');
insert into departments values(default,'外院');
insert into departments values(default,'文院');
insert into departments values(default,'体院');
场景: 查询学生学号、学生姓名、学生专业编号
SELECT
student.stuNumber,
student.name,
departments.id
FROM
student
INNER JOIN departments on student.major = departments.major;
此外还可以在where上指定条件
SELECT
student.stuNumber,
student.name,
departments.id
FROM
student,
departments
WHERE
student.major = departments.major;
结果同上
上面的场景,使用表名称.列名称指定查询哪个表的列,除此之外还可以使用表别名.列名称,这样做的好处让DQL更加简洁
SELECT
s.stuNumber,
s.name,
d.id
FROM
student s,
departments d
WHERE
s.major = d.major;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tpv8Mhce-1649400613980)(https://gitee.com/peanuts-are-delicious/seriousnote/raw/master/Pics10/image-20220406095207182.png)]
小结:多表联合查询在指定列时必须使用"表名称".列名称,或者"表别名".列名称。因为必须告诉MySQL服务器你的列属于那张表。
17.2外连接
A - A∩B 查询两张表都满足的数据,以及左边表(A表)独有的数据(以左边表为主查询表)。
A - A∩B A表的数据 - A交B的数据
关键字:left join on
B - A∩B 查询两张表都满足的数据,以及右边表独有的数据(以右边表为主查询表)。
关键字:right join on
17.3合并查询
概念:将多个DQL语句合并成一个结果集
关键字:union all 和 union
union all 将多个DQL语句合并成一个结果集,不会去掉重复的数据
union 将多个DQL语句合并成一个结果集,会去掉重复的数据
-- 查询院系是计科的所有学生信息
-- 查询所有年龄为18的学生信息
SELECT
*
FROM
student
WHERE
major = '计科' UNION ALL
SELECT
*
FROM
student
WHERE
age = '20';
小结:union能够去掉多个结果集中重复的数据
union all由于没有去重,所以效率高于union
分布式:会学习分库分表,通常将多个查询结果集组装为一个结果
17.4自连接
多个关联查询的表是同一张表,通过取别名的方式生成两张虚拟表
语法:
select 列名称
from 表名称 表别名1 inner/left/right join 表别名 表别名2;
17.5子查询
- where 子查询
场景:筛选出比张三年龄大的学生姓名和年龄。
SELECT
name,age
FROM
student
WHERE
age > (
SELECT age FROM student WHERE name = '张三'
);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C8q6THX5-1649400613981)(https://gitee.com/peanuts-are-delicious/seriousnote/raw/master/Pics10/image-20220406104413865.png)]
- from子查询
场景:计算19岁以上学生男女生平均年龄和最大年龄
SELECT
gender,
avg(age) average_age,
max(age) max_age
FROM
(
SELECT
age,gender
FROM
student
WHERE age > 19
) as temp
GROUP BY
gender;
- in子查询
场景:筛选19岁以上的土木人的所有信息。
SELECT * FROM student WHERE name IN (
SELECT name FROM student WHERE age > 19 AND major = '土木'
);
- exists 子查询
场景:查询是否存在年龄大于19的学生
create table student_major
(
id int unsigned not NULL auto_increment primary key,
major varchar(2) not NULL
);
insert into student_major (major) values('土木');
insert into student_major (major) values('计科');
insert into student_major (major) values('图情');
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ve07ytVa-1649400613982)(https://gitee.com/peanuts-are-delicious/seriousnote/raw/master/Pics10/image-20220406112316851.png)]
select * from student_major where EXISTS (select major from student where age > 19);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J72RkqKn-1649400613983)(https://gitee.com/peanuts-are-delicious/seriousnote/raw/master/Pics10/image-20220406125713012.png)]
- any子查询
查询满足条件的学生
select * from student where major = any(select major from student_major);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fRHZr6wC-1649400613983)(https://gitee.com/peanuts-are-delicious/seriousnote/raw/master/Pics10/image-20220406130204454.png)]
- all子查询
insert into student values (default,'Peanut','男',22,'图情');
delete from student_major where major = '土木' or major = '计科';
select * from student where major = all(select major from student_major);
- 比较运算符子查询
查询Peanut是哪个专业的
select name,major from student where major = all(select major from student where name = 'Peanut');
- 子查询总结
where 型子查询:指把内部查询的结果作为外层查询的比较条件。
from 型子查询:把内层的查询结果当成临时表,供外层 sql 再次查询。
in 子查询:内层查询语句仅返回一个数据列,这个数据列的值将供外层查询语句进行比较。
exists 子查询:把外层的查询结果,拿到内层,看内层是否成立,简单来说后面的返回 true, 外层(也就是前面的语句)才会执行,否则不执行。
any 子查询:只要满足内层子查询中的任意一个比较条件,就返回一个结果作为外层查询条件。
all 子查询:内层子查询返回的结果需同时满足所有内层查询条件。
比较运算符子查询:子查询中可以使用的比较运算符如 “>” 、“<”、“= ” 、“!=”
18.DQL语句执行顺序
2.7.4DCL (Data Control Language) 数据控制语言
数据控制语言 (Data Control Language) 在 SQL 语言中,是一种可对数据访问权进行控制的指令,它可以控制特定用户账户对数据表、查看表、预存程序、用户自定义函数等数据库对象的控制权。由 GRANT 和 REVOKE 两个指令组成。DCL 以控制用户的访问权限为主,GRANT 为授权语句,对应的 REVOKE 是撤销授权语句。DCL 语句主要是 DBA 用来管理系统中的对象权限时所使用,一般的开发人员很少使用。https://baike.baidu.com/item/%E6%95%B0%E6%8D%AE%E6%8E%A7%E5%88%B6%E8%AF%AD%E8%A8%80
1.管理用户
1. 添加用户:
* 语法:CREATE USER '用户名'@'主机名' IDENTIFIED BY '密码';
* 主机名可以用%表示该用户可以从任意地址访问数据库
2. 删除用户:
* 语法:DROP USER '用户名'@'主机名';
3. 修改用户密码:
UPDATE USER SET PASSWORD = PASSWORD('新密码') WHERE USER = '用户名';
UPDATE USER SET PASSWORD = PASSWORD('abc') WHERE USER = 'lisi';
SET PASSWORD FOR '用户名'@'主机名' = PASSWORD('新密码');
SET PASSWORD FOR 'root'@'localhost' = PASSWORD('123');
* mysql中忘记了root用户的密码?
1. cmd -- > net stop mysql 停止mysql服务
* 需要管理员运行该cmd
2. 使用无验证方式启动mysql服务: mysqld --skip-grant-tables
3. 打开新的cmd窗口,直接输入mysql命令,敲回车。就可以登录成功
4. use mysql;
5. update user set password = password('你的新密码') where user = 'root';
6. 关闭两个窗口
7. 打开任务管理器,手动结束mysqld.exe 的进程
8. 启动mysql服务
9. 使用新密码登录。
4. 查询用户:
-- 1. 切换到mysql数据库
USE myql;
-- 2. 查询user表
SELECT * FROM USER;
注:通配符: % 表示可以在任意主机使用用户登录数据库
2.权限管理
1. 查询权限:
-- 查询权限
SHOW GRANTS FOR '用户名'@'主机名';
SHOW GRANTS FOR 'lisi'@'%';
2. 授予权限:
-- 授予权限
grant 权限列表 on 数据库名.表名 to '用户名'@'主机名';
-- 给张三用户授予所有权限,在任意数据库任意表上
GRANT ALL ON *.* TO 'zhangsan'@'localhost';
3. 撤销权限:
-- 撤销权限:
revoke 权限列表 on 数据库名.表名 from '用户名'@'主机名';
REVOKE UPDATE ON db3.`account` FROM 'lisi'@'%';
2.7.5Transaction Control Language(TCL) 事务控制命令
These commands are used to control and manage database transactions.
这些命令用于控制和管理数据库事务。
1.事务简介
- TCL:TransactionControlLanguage,事务控制语言
- 事务:
一个或一组 SQL 语句
组成的一个执行单元,这个执行单元要么全部执行,要么全部不执行 - 案例:A 向 B 转账,涉及两个账户,一个账户需要加钱,另一个账户需要减钱,这两个操作的结果需要保持一致,即要么都成功,要么都失败,此时就可以通过事务来解决
- 事务由单独单元的一个或多个 SQL 语句组成,在这个单元中,每个 MySQL 语句时相互依赖的。而整个单独单元作为一个不可分割的整体。如果单元中一条 SQL 语句执行失败或产生错误,整个单元都会
回滚
。所有受到影响的数据将返回到事物开始之前的状态;如果单元中的语句均执行成功,则事务被顺利运行
2.存储引擎
- 概念:在 MySQL 中的数据用于各种不同的技术存储在文件(或内存)中,也叫表类型
- 通过
show engines
查看 MySQL 支持的存储引擎 - 在 MySQL 中用的最多的存储引擎有:innodb、MyISam、memory 等。其中 innodb 支持事务,其他两个不支持
3.事务的ACID属性
- 原子性(Atomicity):原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生
- 一致性(Consistency):事务必须使数据库从一个一致性状态变换到另一个一致性状态
- 隔离性(Isolation):事务的隔离性是指一个事务的执行不能被其他事务所干扰,即一个事务的内部操作及使用的数据对并发的其他事务没有影响
- 持久性(Durability):指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响
4.事务的创建
- 隐式事务:事务没有明显的开启和结束标记,如 insert、update、delete 语句
- 显示事务:事务具有明显的开始和结束标记,前提是先设置自动提交功能为禁用
- 步骤一:
set autocommit = 0;
:关闭自动提交,只对当前事务有效start transation;
开始标记,可以省略
- 步骤二:
- 编写事务的相关语句
- 步骤三:
commit;
:提交执行事务rollback;
回滚事务
# 开启事务
SET AUTOCOMMIT = 0;
START TRANSACTION;
# 编写一组事务语句
UPDATE student
SET
major = '睡觉'
WHERE
name = 'Peanut';
UPDATE student
SET
major = '吃饭'
WHERE
name = '张三';
# 结束事务
COMMIT;
5.事务的隔离级别
对于同时运行的多个事务,当这些事务访问数据库中相同的数据时,如果没有采取必要的隔离机制,就会导致各种并发问题:
脏读
:对于两个事务 T1、T2,T1 读取了已经被 T2 更新但还没有被提交的字段,之后,若 T2 回滚,T1 读取的内容就是临时且无效的不可重复度
:对于两个事务 T1,T2,T1 读取了一个字段,然后 T2 更新了该字段,之后,T1 再次读取同一个字段时,发现值被修改幻读
:对于两个事务 T1、T2,T1 从表中读取了一个字段,然后 T2 在该表中插入了一些新的行。之后,如果 T1 再次读取同一个表,就会多出几行
数据库事务的隔离性:数据库系统必须具有隔离并发运行各个事务的能力,使它们不会互相影响,避免出现各种并发问题
数据库提供四种隔离级别:
读未提交
(READ UNCOMMITED):允许事务读取未被其它事务提交的变更,会出现脏读、不可重复读和幻读读已提交
(READ COMMITED):只允许事务读取已经被其他事务提交的变更,可以避免脏读,但不可避免不可重复读和幻读可重复读
(REPETABLE READ):确保事务可以多次从一个字段中读取相同的值,在这个事务持续期间,禁止其他事务对这个字段进行更新。可以避免脏读和不可重复读,但幻读的问题仍然存在串行化
(SERIALIZABLE):确保事务可以从一个表中读取相同的行。在这个事务执行期间,禁止其他事务对该表进行插入、删除、修改操作,所有并发问题都能避免,但是会导致性能下降
Oracle 只支持读已提交和串行化两种隔离级别,默认为读已提交,MySQL 支持所有四种隔离级别,MySQL 默认为可重复读
在事务中使用SAVEPOINT 保存点
可以设置保存点,在回滚时可以使用ROLLBACK TO 保存点
将事务回滚到保存点而不是事务执行之前。
6.delete 和 trancate 在事务中的区别
- delete
SET AUTOCOMMIT = 0;
START TRANSACTION;
DELETE
FROM
student WHERE name = 'Peanut';
ROLLBACK;
撤销后数据还在
- trancate
SET AUTOCOMMIT = 0;
START TRANSACTION;
TRUNCATE TABLE student1;
ROLLBACK;
撤销后数据不在
- 总结:事务中的 delete 操作可以被回滚,而 trancate 操作由于直接提交到磁盘,因此不能回滚恢复数据
2.8函数
1.数字函数
函数 | 说明 |
---|---|
ABS(x) | 返回 x 的绝对值 |
AVG(expression) | 返回一个表达式的平均值,expression 是一个字段 |
CEIL(x)/CEILING(x) | 返回大于或等于 x 的最小整数 |
FLOOR(x) | 返回小于或等于 x 的最大整数 |
EXP(x) | 返回 e 的 x 次方 |
GREATEST(expr1, expr2, expr3, …) | 返回列表中的最大值 |
LEAST(expr1, expr2, expr3, …) | 返回列表中的最小值 |
LN | 返回数字的自然对数 |
LOG(x) | 返回自然对数 (以 e 为底的对数) |
MAX(expression) | 返回字段 expression 中的最大值 |
MIN(expression) | 返回字段 expression 中的最大值 |
POW(x,y)/POWER(x,y) | 返回 x 的 y 次方 |
RAND() | 返回 0 到 1 的随机数 |
ROUND(x) | 返回离 x 最近的整数 |
SIGN(x) | 返回 x 的符号,x 是负数、0、正数分别返回 -1、0 和 1 |
SQRT(x) | 返回 x 的平方根 |
SUM(expression) | 返回指定字段的总和 |
TRUNCATE(x,y) | 返回数值 x 保留到小数点后 y 位的值(与 ROUND 最大的区别是不会进行四舍五入) |
2.字符串函数
函数 | 说明 |
---|---|
ASCII(s) | 返回字符串 s 的第一个字符的 ASCII 码 |
LENGTH/CHAR_LENGTH(s)/CHARACTER_LENGTH(s) | 返回字符串 s 的字符数 |
CONCAT(s1,s2…sn) | 字符串 s1,s2 等多个字符串合并为一个字符串 |
FIND_IN_SET(s1,s2) | 返回在字符串 s2 中与 s1 匹配的字符串的位置 |
FORMAT(x,n) | 函数可以将数字 x 进行格式化 “#,###.##”, 将 x 保留到小数点后 n 位,最后一位四舍五入 |
INSERT(s1,x,len,s2) | 字符串 s2 替换 s1 的 x 位置开始长度为 len 的字符串 |
LOCATE(s1,s) | 从字符串 s 中获取 s1 的开始位置 |
LCASE(s)/LOWER(s) | 将字符串 s 的所有字母变成小写字母 |
UCASE(s)/UPPER(s) | 将字符串 s 的所有字母变成大写字母 |
TRIM(s) | 去掉字符串 s 开始和结尾处的空格 |
LTRIM(s) | 去掉字符串 s 开始处的空格 |
RTRIM(s) | 去掉字符串 s 结尾处的空格 |
SUBSTR(s, start, length) | 从字符串 s 的 start 位置截取长度为 length 的子字符串 |
SUBSTR/SUBSTRING(s, start, length) | 从字符串 s 的 start 位置截取长度为 length 的子字符串 |
POSITION(s1 IN s) | 从字符串 s 中获取 s1 的开始位置 |
REPEAT(s,n) | 将字符串 s 重复 n 次 |
REVERSE(s) | 将字符串 s 的顺序反过来 |
STRCMP(s1,s2) | 比较字符串 s1 和 s2,如果 s1 与 s2 相等返回 0 ,如果 s1>s2 返回 1,如果 s1<s2 返回 -1 |
3.日期函数
函数 | 说明 |
---|---|
CURDATE()/CURRENT_DATE() | 返回当前日期 |
CURRENT_TIME()/CURTIME() | 返回当前时间 |
CURRENT_TIMESTAMP() | 返回当前日期和时间 |
ADDDATE(d,n) | 计算起始日期 d 加上 n 天的日期 |
ADDTIME(t,n) | 时间 t 加上 n 秒的时间 |
DATE() | 从日期或日期时间表达式中提取日期值 |
DAY(d) | 返回日期值 d 的日期部分 |
DATEDIFF(d1,d2) | 计算日期 d1->d2 之间相隔的天数 |
DATE_FORMAT(f) | 按表达式 f 的要求显示日期 d |
DAYNAME(d) | 返回日期 d 是星期几,如 Monday,Tuesday |
DAYOFMONTH(d) | 计算日期 d 是本月的第几天 |
DAYOFWEEK(d) | 日期 d 今天是星期几,1 星期日,2 星期一,以此类推 |
EXTRACT(type FROM d) | 从日期 d 中获取指定的值,type 指定返回的值 type 可取值为: MICROSECOND SECOND MINUTE HOUR DAY WEEK MONTH QUARTER YEAR SECOND_MICROSECOND MINUTE_MICROSECOND MINUTE_SECOND HOUR_MICROSECOND HOUR_SECOND HOUR_MINUTE DAY_MICROSECOND DAY_SECOND DAY_MINUTE DAY_HOUR YEAR_MONTH |
DAYOFWEEK(d) | 日期 d 今天是星期几,1 星期日,2 星期一,以此类推 |
UNIX_TIMESTAMP() | 得到时间戳 |
FROM_UNIXTIME() | 时间戳转日期 |
4.高级函数
4.1CASE函数
CASE 函数,类似于 Java 中 Switch 语句
语法:
CASE
WHEN condition1 THEN result1
WHEN condition2 THEN result2
WHEN conditionN THEN resultN
ELSE result
END;
create table student2 (select
stuNumber,name,age
,case
when major = '土木' then '[工科]'
when major in ('外院','文院') then '[文科]'
when major = '计科' then '[理科]'
else '[COOL!]'
end
as category from student);
4.2IF函数
IF() 函数在条件为 TRUE 时返回一个值,如果条件为 FALSE 则返回另一个值。
语法:IF(condition, value_if_true, value_if_false)
# IF语句
select
s.* ,if(age >=18,'成年人','青少年') '是否成年',if(gender='男',1,0) '性别'
from student s;
4.3IFNULL函数
如果表达式为 NULL,则 IFNULL() 函数返回指定的值。如果表达式为 NOT NULL,则此函数返回表达式。
语法:IFNULL(expression, alt_value)
# IFNULL 函数
select s.* ,ifnull(sex,"未知") '性别' from students s;
4.4ISNULL 函数
ISNULL() 函数返回 1 或 0,具体取决于表达式是否为 NULL。如果 expression 为 NULL,则此函数返回 1. 否则,返回 0。
语法:ISNULL(expression)
# ISNULL() 函数
select s.* ,ISNULL(sex) '性别' from students s;
4.5NULLIF 函数
NULLIF() 函数比较两个表达式,如果它们相等则返回 NULL。 否则,返回第一个表达式。
语法:NULLIF(expr1, expr2)
# NULLIF函数 如果两个表达式相同就返回null,否则返回第一个表达式
select NULLIF('a','b'),NULLIF('a1','a1') ;
4.6CAST 函数
CAST() 函数将(任何类型的)值转换为指定的数据类型。
语法:CAST(value AS datatype)
# CAST函数
select CAST('2022-02-13' as DATE) ;
select CAST('2022-02-13 12:12:24' as TIME) ;
select CAST(97 as CHAR) ;
select CAST(5-20 as SIGNED) ;
select CAST(12.666 as DECIMAL);
select CAST('66' as BINARY);
3.MySQL分库分表
3.1为什么要分库分表
解决大数据存储时数据访问性能,具体来说就是解决超大容量
问题和性能
问题。
举例说明,订单表或用户表如果数据量达到上亿条记录,此时数据库的 IO 能力、处理能力就会出现一个瓶颈(MySQL 官方统计单表数据量
超过 1000 万性能会逐渐下降),所以要进行分表
。另一方面,单一数据库
本身的 CPU、内存、磁盘、IO 都有性能极限,所以要进行分库
。
单库太大
单个数据库处理能力有限;单库所在服务器上磁盘空间不足;单库上操作的 IO 瓶颈 。
解决方法:切分成更多更小的库。
3.2如何分库分表
一般就是**垂直切分
和水平切分
,这是一种结果集描述的切分方式,是物理空间上的切分。
我们从面临的问题,开始解决,阐述: 首先是用户请求量太大,我们就堆机器搞定(这不是本文重点)。然后是单个库太大,这时我们要看是因为表多而导致数据多,还是因为单张表里面的数据多。
如果是因为表多
而单库数据多**,使用**垂直切分
,根据业务将表切分到不同的库。
如果是因为单张表
的数据量太大导致单库数据多**,这时要用**水平切分
**,即把表的数据按某种规则切分成多张表,甚至多个库上的多张表。
分库分表的顺序
应该是先垂直分,后水平分
。 因为垂直分更简单,更符合我们处理现实世界问题的方式。
垂直拆分
1. 垂直分表
也就是 “大表拆小表
”,基于列字段
进行的。一般是表中的字段较多,将不常用
的, 数据较大,长度较长(比如 text 类型
字段)的拆分到“扩展表
“。一般是针对那种几百列的大表,也避免查询时,数据量太大造成的“跨页” 问题。
2. 垂直分库
垂直分库针对的是一个系统
中的不同业务
进行拆分,比如用户 User 一个库,商品 Producet 一个库,订单 Order 一个库。 切分后,要放在多个服务器
上,而不是一个服务器上。为什么? 我们想象一下,一个购物网站对外提供服务,会有用户,商品,订单等的 CRUD。没拆分之前, 全部都是落到单一的库上的,这会让数据库的单库处理能力成为瓶颈。按垂直分库后,如果还是放在一个数据库服务器上, 随着用户量增大,这会让单个数据库的处理能力成为瓶颈,还有单个服务器的磁盘空间,内存,tps(系统吞吐量)等非常吃紧。 所以我们要拆分到多个服务器上,这样上面的问题都解决了,以后也不会面对单机资源问题。
数据库业务层面的拆分,和服务的 “治理”,“降级” 机制类似,也能对不同业务的数据分别的进行管理,维护,监控,扩展等。 数据库往往最容易成为应用系统的瓶颈,而数据库本身属于 “有状态” 的,相对于 Web 和应用服务器来讲,是比较难实现 “横向扩展” 的。 数据库的连接资源比较宝贵且单机处理能力也有限,在高并发
场景下,垂直分库
一定程度上能够突破 IO、连接数及单机硬件资源的瓶颈。
水平拆分
1. 水平分表(单库下)
针对数据量巨大的单张表(比如订单表),按照某种规则(RANGE,HASH 取模等),切分到多张表里面去。 但是这些表还是在同一个库中,所以库级别的数据库操作还是有 IO 瓶颈。不建议采用。
2. 水平分库分表(多库下)
将单张表的数据切分到多个服务器上去,每个服务器具有相应的库与表,只是表中数据集合不同。 水平分库分表能够有效的缓解单机和单库的性能瓶颈和压力,突破 IO、连接数、硬件资源等的瓶颈。
水平分库分表切分规则
1.RANGE 范围切分
按照某个字段(例如 ID)在某个维度区间将数据路由映射到不同表或数据库中。例如 ID=0-100000 之间的数据保存奥数据库 DB1,ID=100001~200000 之间的数据保存至数据库 DB2。范围切分能保证数据是连续的。
2.HASH 取模
例如订单表,可以按照订单 userid 字段进行哈希取模算法,路由映射到不同表或数据库中。一致性 Hash 数据存储具有随机性。
3.地理区域
比如按照华东,华南,华北这样来区分业务,七牛云应该就是如此。
4.时间切分
按照时间切分,就是将 6 个月前,甚至一年前的数据切出去放到另外的一张表,因为随着时间流逝,这些表的数据 被查询的概率变小,所以没必要和 “热数据” 放在一起,这个也是“冷热数据分离”。
3.3分库分表后面临的问题
1. 事务支持
分库分表后,就成了分布式事务了,多个数据库表之间需要保证原子性。
如果依赖数据库本身的分布式事务管理功能去执行事务,将付出高昂的性能代价; 如果由应用程序去协助控制,形成程序逻辑上的事务,又会造成编程方面的负担,所以需要分布式事务的解决方案。
2. 跨库 join 的问题 select a.x,b.y from user a join merchant b on a.id=b.userid
分库分表后表之间的关联操作将受到限制,我们无法 join
位于不同分库的表
,也无法 join 分表粒度不同的表, 结果原本一次查询能够完成的业务,可能需要多次查询才能完成。
解决方法:
设计
的时候充分考虑到应用层的 join
问题,尽量避免跨库 join;- 关联表数据可以通过
服务层
去远程 RPC 调用,例如上述 sql 语句,可以先本地查询出 a 表数据,然后通过远程 RPC 调用获取关联 b 表数据; - 创建
全局表
,即基础数据
在每个数据库中都创建相同的表,数据变更较少的基于全局应用的表; - 做
字段冗余
,用空间换时间,例如在订单表中保存商户 id,商户名称。
3. 跨分片数据排序分页
解决方法:
在应用层
进行数据拼接,对每个表中的数据进行查询,然后按照排序字段再进行数据拼接。
4. 唯一主键问题
例如用自增 ID 做主键,分库后必然会出现重复主键。
解决方法:
- 用 UUID 作为主键,UUID 字符串比较大,造成生成的索引较大,性能较低;
- 利用 Snowflake 雪花算法生成主键,根据时间序列、机器标识、技术顺序号,按照指定算法生成唯一 ID;
- 借助 MongoDB 的 ObjectId 作为唯一主键;
- 借助 zookeeper 自动生成递增 ID 作为唯一主键。
3.4MySQL主从复制实现数据库同步
刚开始我们只用单机数据库就够了,随后面对越来越多的请求,我们将数据库的**写操作
和读操作
进行分离, 使用多个从库副本(Slaver Replication)负责读
,使用主库(Master)负责写
, **从库从主库同步更新数据,保持数据一致
。架构上就是数据库主从同步。 从库
可以水平
扩展,分散请求到多个服务器
上,所以更多的读请求不成问题。
但是当用户量级上来后,写请求越来越多,该怎么办?加一个 Master 是不能解决问题的, 因为数据要保存一致性,写操作需要 2 个 master 之间同步,相当于是重复了,而且更加复杂。这时就需要用到上面讲的分库分表(sharding),对写操作进行切分了。
绝大部分应用是一个写少读多
的操作,只读数据库会从主数据库同步数据。MySQL 数据库的读写分离,通常做法是采用 MySQL 主从复制实现数据库同步,由从数据库提供只读操作。
1.主从同步原理
1、master 记录二进制日志 binlog
。在每个事务更新数据完成之前,master 会在二进制日志中记录这些改变。MySQL 将事务串行
的写入二进制日志,即使事务中的语句都是交叉执行的。在事件写入二进制日志完成后,master 通知存储引擎提交事务。
2、slave 将 master 的 binlog 拷贝到它自己的中继日志 relaylog
。slave 首先会开始一个工作线程即 I/O 线程,I/O 线程在 master 上打开一个普通的连接,之后开始 binlog dump process。binlog dump process 从 master 的二进制日志 binlog 中读取事件并写入中继日志 relaylog,如果已经跟上 master,它会睡眠并等待 master 产生新的事件。
3、SQL 线程从中继日志读取事件,并重放其中的事件去更新 slave 的数据,使其与 master 中的数据一致。
2.Windows环境主从搭建
1.下载解压zip文件,重命名文件夹为mysql-master;拷贝一份更改文件夹名称为mysql-slave.
2.在mysql-master目录下新建my.ini
文件,添加以下内容。
[client]
# 设置mysql客户端连接服务端时默认使用的端口
port=3307
default-character-set=utf8
[mysqld]
#主库配置
server-id=1
#开启二进制日志
log_bin=master-bin
log_bin-index=master-bin.index
# 设置3307端口
port=3307
# 设置mysql的安装目录
basedir=D:/MySQL8/mysql-master
# 设置mysql数据库的数据的存放目
datadir=D:/MySQL8/mysql-master/data
# 允许最大连接数
max_connections=200
# 允许连接失败的次数。
max_connect_errors=10
# 服务端使用的字符集默认为UTF8
character-set-server=utf8
# 创建新表时将使用的默认存储引擎
default-storage-engine=INNODB
# 默认使用“mysql_native_password”插件认证
#mysql_native_password
default_authentication_plugin=mysql_native_password
3.以管理员身份运行命令提示符
,输入cd D:\MySQL8\mysql-master\bin
,输入mysqld --initialize --console
(bin目录下生成data文件,系统默认创建数据库,此时还会生成一个临时的密码)
4.注册服务,输入命令:
mysqld --install mysql-master --defaults-file="D:\MySQL8\mysql-master\my.ini"
5.启动 MySQL 服务,修改密码
net start mysql-master
#登陆 mysql,输入命令:
mysql -u root -P3307 -p
-- 修改密码,输入命令:
ALTER USER 'root'@'localhost' IDENTIFIED BY '123456';
#退出 mysql,输入命令:
exit;
#重新登陆 OK。恭喜,主库完成!!!
6.slave从库配置
[client]
# 设置mysql客户端连接服务端时默认使用的端口
port=3308
default-character-set=utf8
[mysqld]
#主库配置
server-id=2
#开启二进制日志
log_bin=slave-relay-bin
log_bin-index=slave-relay-bin.index
# 设置3308端口
port=3308
# 设置mysql的安装目录
basedir=D:/MySQL8/mysql-slave
# 设置mysql数据库的数据的存放目
datadir=D:/MySQL8/mysql-slave/data
# 允许最大连接数
max_connections=200
# 允许连接失败的次数。
max_connect_errors=10
# 服务端使用的字符集默认为UTF8
character-set-server=utf8
# 创建新表时将使用的默认存储引擎
default-storage-engine=INNODB
# 默认使用“mysql_native_password”插件认证
#mysql_native_password
default_authentication_plugin=mysql_native_password
cd D:\MySQL8\mysql-slave\bin
mysqld --initialize --console
mysqld --install mysql-slave --defaults-file="D:\MySQL8\mysql-slave\my.ini"
net start mysql-slave
mysql -u root -p
ALTER USER 'root'@'localhost' IDENTIFIED BY '1234';
7.主库 (master) 关联从库 (slave) 配置
登陆 master 主库,创建一个用于让从数据库连接的用户,输入命令 (自定义用户 peanut,密码为 peanut123)
net start mysql-master
cd D:\MySQL8\mysql-master\bin
mysql -uroot -p
CREATE USER 'peanut'@'%' IDENTIFIED WITH mysql_native_password BY 'peanut123';
#给用户授权,输入命令
GRANT REPLICATION SLAVE ON *.* TO 'peanut'@'%';
#刷新权限,输入命令
flush privileges;
-- 查看 master 的状态,输入命令
show master status;
登陆 slave 从库,在 slave 从库节点上设置 master 主库主节点参数,输入命令
/*注意,MASTER_LOG_FILE 和 master 状态里的 File 保持一致,MASTER_LOG_POS 和 master 状态里的 Positon 保持一致*/
CHANGE MASTER TO
MASTER_HOST='127.0.0.1',MASTER_PORT=3307,
MASTER_USER='peanut',
MASTER_PASSWORD='peanut123',
MASTER_LOG_FILE='master-bin.000004',
MASTER_LOG_POS=831;
#开启主从同步,输入命令
start slave;
#查看主从同步状态,输入命令
show slave status\G;
#Slave_IO_Running 和 Slave_SQL_Running 的状态都为 YES 才表示同步成功!!!!
8.验证
4.Python与MySQL
数据库表是一个二维表
,包含多行多列。把一个表的内容用 Python 的数据结构表示出来的话,可以用一个 list 表示多行,list 的每一个元素是 tuple,表示一行记录,比如,包含id
和name
的user
表:
[
('1', 'Michael'),
('2', 'Bob'),
('3', 'Adam')
]
Python 的 DB-API 返回的数据结构就是像上面这样表示的。
但是用 tuple 表示一行很难看出表的结构。如果把一个 tuple 用 class 实例来表示,就可以更容易地看出表的结构来:
class User(object):
def __init__(self, id, name):
self.id = id
self.name = name
[
User('1', 'Michael'),
User('2', 'Bob'),
User('3', 'Adam')
]
这就是传说中的 ORM
技术:Object-Relational Mapping
,把关系数据库的表结构映射到对象上。是不是很简单?
但是由谁来做这个转换呢?所以 ORM 框架应运而生。
在 Python 中,最有名的 ORM 框架是 SQLAlchemy
。我们来看看 SQLAlchemy 的用法。
首先通过 pip 安装 SQLAlchemy:
$ pip install sqlalchemy==1.4.32 -i https://pypi.douban.com/simple/
然后,利用上次我们在 MySQL 的 test 数据库中创建的user
表,用 SQLAlchemy 来试试:
1.第一步,导入 SQLAlchemy,并初始化 DBSession:
# 导入:
from sqlalchemy import Column, String, create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
# 初始化数据库连接:
engine = create_engine('mysql+pymysql://root:123456@localhost:3306/test')
# 创建DBSession类型:
DBSession = sessionmaker(bind=engine)
# 创建对象的基类:
BaseModel = declarative_base()
2.定义表结构
from sqlalchemy import Table, Column, Integer, String
#定义对象
class User(BaseModel):
# 表名
__tablename__ = 'user'
# 表结构,其中ID设为是主键,并且是自动增加的
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(20))
age = Column(Integer)
3.创建以及删除表
对于创建表以及删除表的操作,代码如下
#创建映射的数据库表
def init_db():
BaseModel.metadata.create_all(engine)
#删除映射的数据库表
def drop_db():
BaseModel.metadata.drop_all(engine)
4.插入数据
我们可以尝试往新建的表格当中插入几个值,代码如下
def insert_data(name_1, age_1):
# 创建session对象,相当于MySQLdb里面的游标
session = DBSession()
# 创建新User对象:
new_user = User(name=name_1, age=age_1)
# 添加到session:
session.add(new_user)
# 提交添加数据的操作
session.commit()
# 关闭session
session.close()
if __name__ == "__main__":
init_db()
insert_data(name_1="Mike", age_1=20)
insert_data(name_1="John", age_1=35)
5.查询
要是我们想要查询表格中的数据,可以这么来做
# 创建Session:
session = DBSession()
# 创建Query查询,filter是where条件,最后调用one()返回唯一行,如果调用all()则返回所有行:
user = session.query(User).filter(User.name == 'Mike').one()
# 打印类型和对象的name属性和age属性:
print(user.name, user.age)
# 关闭Session:
session.close()
要是调用的是all()
则返回所有行,因此我们需要通过for
循环遍历出来的结果然后打印,代码如下
# 创建Session:
session = DBSession()
# 创建Query查询,filter是where条件,最后调用one()返回唯一行,如果调用all()则返回所有行:
users = session.query(User).all()
# 打印类型和对象的name属性和age属性:
for u in users:
print(u.name, u.age)
# 关闭Session:
session.close()
6.更新和删除数据
我们尝试来更新表格中的一些数据,代码如下
# 创建Session:
session = DBSession()
# 可以进行多条数据更新
user = session.query(User).filter(User.id == 2)
user.update({User.age: 30})
# 提交数据
session.commit()
# 关闭Session
session.close()
删除表格当中的一些值,代码如下
# 创建Session
session = DBSession()
# 删除哪些数据
user = session.query(User).filter(User.id == 2).one()
session.delete(user)
# 提交数据
session.commit()
# 关闭session
session.close()
7.直接运行SQL
语句
当然我们在创建session
之后,我们也可以在里面直接运行SQL
语句,例如我们想要查看一下总共有哪些数据库,代码如下
session = DBSession()
print(session.execute('show databases;').fetchall())
session.close()
session = DBSession()
session.execute("insert into user values (NULL,'Ha',22)")
session.commit()
session.close()
8.DataFrame
到MySQL
数据库
我们同时也可以批量的将excel
或者csv
文件当中的数据批量的导入到MySQL
数据库当中,我们先通过Pandas
读取文件中的数据,代码如下
import pandas as pd
from sqlalchemy import create_engine
sql_connect = 'mysql+pymysql://root:123456@localhost:3306/test?charset=utf8'
engine = create_engine(sql_connect)
df = pd.read_excel("test.xlsx")
df.to_sql("user", engine, index=False, if_exists='append')
当然我们也可以从数据库的某个表格当中来读取数据,代码如下
df = pd.read_sql("student", engine)
print(df.head())
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4tXZP3Jy-1649400613996)(https://gitee.com/peanuts-are-delicious/seriousnote/raw/master/Pics10/image-20220407224030873.png)]
小结
ORM 框架的作用就是把数据库表的一行记录与一个对象互相做自动转换。
正确使用 ORM 的前提是了解关系数据库的原理。
5.参考资料
[1]佚名. MySQL Cheatsheet[EB/OL].[2022–04–04].https://devhints.io/mysql.
[2]佚名. Comprehensive MySQL Cheat Sheet For Quick Reference[EB/OL].[2022–04–04].https://www.softwaretestinghelp.com/mysql-cheat-sheet/.
[3]佚名. MySQL Cheat Sheet[EB/OL].[2022–04–04].https://cheatography.com/davechild/cheat-sheets/mysql/.
[4]点击关注👉. 21 分钟 MySQL 入门教程完整版[EB/OL].[2022–04–04].http://mp.weixin.qq.com/s?__biz=Mzk0OTI1OTQ2MQ==&mid=2247504752&idx=2&sn=391ed23365a9616822784231998aa4a8&chksm=c3598edaf42e07cc28f0f6553008fb7fd6574b8ca05c13af52b871878d5f4533505c1f2b594a#rd.
[5]佚名. (20条消息) MySQL基础篇(DDL,DML,DQL,DCL详细讲解)_波波烤鸭的博客-CSDN博客[EB/OL].[2022–04–04].https://blog.csdn.net/qq_38526573/article/details/122915844?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164908239416780261934888%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=164908239416780261934888&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~times_rank-2-122915844.142v5pc_search_result_control_group,157v4control&utm_term=DDL%EF%BC%8CDML%EF%BC%8CDQL%EF%BC%8CDCL.
[6]佚名. mysql 外键的基本使用 - 阿尔托莉雅`潘德拉贡 - 博客园[EB/OL].[2022–04–05].https://www.cnblogs.com/wanghaoyu666/archive/2019/09/04/11460081.html.
[7]佚名. InnoDB存储引擎-表 - 掘金[EB/OL].[2022–04–05].https://juejin.cn/post/6946059131044233247.
[8]佚名. (20条消息) MySQL:DCL_pwlwell的博客-CSDN博客[EB/OL].[2022–04–05].https://blog.csdn.net/pwlwell/article/details/104878105.
[9]佚名. (20条消息) 数据库DQL语句_啊圈圈的博客-CSDN博客_dql语句[EB/OL].[2022–04–05].https://blog.csdn.net/pangpangjinhhh/article/details/123329568?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164914757816782089323422%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=164914757816782089323422&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~times_rank-1-123329568.142v5pc_search_result_control_group,157v4control&utm_term=DQL.
[10]佚名. 输入法中全角半角的区别_百度知道[EB/OL].[2022–04–06].https://zhidao.baidu.com/question/7818997.html.
[11]佚名. (20条消息) MySQL DQL知识整理_才疏学浅的小缘同学的博客-CSDN博客[EB/OL].[2022–04–06].https://blog.csdn.net/qq_44790505/article/details/119883478?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164914757816782089323422%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=164914757816782089323422&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~times_rank-8-119883478.142v5pc_search_result_control_group,157v4control&utm_term=DQL.
[12]佚名. (20条消息) 子查询(7种类型)_机智的豆子的博客-CSDN博客_子查询[EB/OL].[2022–04–06].https://blog.csdn.net/qq_39380737/article/details/81127497.
[13]佚名. 【MySQL】TCL事务控制语言与视图 - 叩町coding[EB/OL].[2022–04–06].https://hxuanyu.com/mysql_tcl_view.html.
[14]佚名. (20条消息) 数据库分库分表及MySQL主从复制_Ysming88的博客-CSDN博客[EB/OL].[2022–04–06].https://blog.csdn.net/m0_45861545/article/details/121844353?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164921085916780255291006%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=164921085916780255291006&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~times_rank-1-121844353.142v5pc_search_result_control_group,157v4control&utm_term=%E6%95%B0%E6%8D%AE%E5%BA%93%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A8.
[15]佚名. (20条消息) 超详细!MySQL如何实现主从复制和读写分离(原理详解和实操)_zzzf98的博客-CSDN博客_mysql主从复制与读写分离[EB/OL].[2022–04–06].https://blog.csdn.net/qq_41786285/article/details/109304126.
[16]佚名. (20条消息) windows系统mysql8同步_windows下mysql-8.0.13主从同步配置方案(读写分离)_芈十四的博客-CSDN博客[EB/OL].[2022–04–06].https://blog.csdn.net/weixin_32365483/article/details/113688348.
[17]俊欣. 【原创内容】当Python需要与数据库交互时,这个模块就变得超级好用[EB/OL].[2022–04–07].http://mp.weixin.qq.com/s?__biz=Mzk0NzI3ODMyMA==&mid=2247498919&idx=1&sn=04d7f354351a0f77b5215f2d6fbd13dd&chksm=c37be438f40c6d2e83ad36cc08dd0fc2d2a7235d8c00b46267c7fc9eb5a258d14e91d13861cd#rd.
[18]佚名. 使用SQLAlchemy - 廖雪峰的官方网站[EB/OL].[2022–04–07].https://www.liaoxuefeng.com/wiki/1016959663602400/1017803857459008.
[19]佚名. SQLAlchemy 1.4 / 2.0 Tutorial — SQLAlchemy 1.4 Documentation[EB/OL].[2022–04–07].https://docs.sqlalchemy.org/en/14/tutorial/index.html.