文章目录
- 数据库操作
-
- 创建数据库
- 查看数据库
- 修改数据库编码
- 删除数据库
- 选择数据库
- 常用数据类型
-
- 整数
- 小数
- 位类型
- 字符、文本
- 枚举
- 集合类型 set
- 日期
- 二进制
- JSON类型
- 空间类型
- 数据表操作
-
- 创建表
- 查看表
- 修改表字段
- 重命名表
- 删除表
- 清空表
- 提交与回滚
-
- 提交commit
- 回滚rollback
- 表数据操作
-
- 运算符
- 添加
- 查询
-
- 简单查询
- 带条件查询
- 模糊查询
- 排序
- 分页
- 聚合函数
- 分组
- 子查询
- 多表连接
- 合并查询结果集
- 删除
- 修改
- 常用函数
-
- 日期和时间类型函数
- 字符处理函数
- 流程控制函数
- 约束
-
- 非空约束
- 主键约束
- 外键约束
- 唯一约束
- 自增约束
- 检查约束
- 默认值约束
- 视图
-
- 创建视图
- 删除视图
- 修改视图
- 对视图进行操作(增、删、改、查)
- 变量
-
- 系统变量
- 用户自定义变量
- 局部变量
- 存储过程
-
- 存储过程的创建
-
- 无参
- 有参
- 存储过程的调用
- 查看创建的存储过程
- 删除存储过程
- 自定义函数
-
- 函数的创建
- 函数调用
- 查看存储函数
- 删除存储函数
- 流程控制
-
- IF语句
- CASE语句
- LOOP循环
- WHILE循环
- REPEAT循环
- 跳转语句
- 游标
- 异常处理
- 触发器
-
- 创建触发器
- 查看创建的触发器
- 删除触发器
数据库操作
创建数据库
数据库环境:MySQL8.0.26
图形化界面:MySQL Workbench
简单创建
使用"create database"关键字可以创建数据库,格式如下:
sql
create database 数据库名;
创建数据库testDatabase1:
sql
#创建数据库testDatabase1
create database testDatabase1;
if not exists关键字
上面可以简单创建一个数据库,但是如果创建的数据库已经存在的话是会报错的,使用"if not exists"关键字可以不发生这种错误,格式如下:
sql
create database if not exists 数据库名
这句话意思是:如果不存在这个数据库,则创建这个数据库;如果存在,则不创建。
sql
#创建数据库testDatabase1
create database if not exists testDatabase1;
指定编码格式
在创建时还可以指定数据库的字符编码,使用"character set"关键字:
sql
#创建数据库并指定编码格式
create database if not exists testDatabase2 character set 'utf8';
查看数据库
1.使用"show database"命令可以查看当前连接中的所有数据库
sql
#查看当前连接中已创建的数据库
show databases;
2.使用"show create database"可以查看指定数据库的创建时的信息,包括字符编码等,格式如下:
sql
show create database 数据库名;
sql
#查看数据库testDatabase1的信息
show create database testDatabase1;
修改数据库编码
使用"alter database"关键字可以修改数据库的字符编码,如下:
sql
#修改数据库testDatabase1编码为gbk
alter database testDatabase1 character set 'gbk';
删除数据库
简单删除
使用"drop database"关键字可以删除一个已创建的数据库,格式如下:
sql
drop database 数据库名;
sql
#删除数据库testDatabase1
drop database testDatabase1;
if exists关键字
直接使用"drop database"虽然可以删除数据库,但是,如果要删除的数据库不存在,就会报错,使用if exists关键字可以很好地解决这个问题:
sql
drop database if exists 数据库名;
如果存在这个数据库,就删除;如果不存在,则不删除。
sql
#删除数据库testDatabase1
drop database if exists testDatabase1;
选择数据库
使用"use"关键字可以选择使用指定数据库
sql
use 数据库名;
常用数据类型
创建数据库表时,需要创建数据库表中的字段,这些字段可以是不同的数据类型,在MySQL中,常用数据类型主要有如下几种类型。
整数
类型 | 占用空间(字节) | 有符号值范围 | 无符号值范围 |
---|---|---|---|
tinyint | 1 | -128~127 | 0~255 |
smallint | 2 | -32768~32767 | 0~65535 |
mediumint | 3 | -8388608~8388607 | 0~16777215 |
int、integer | 4 | -2147483648~2147483647 | 0~4294967295 |
bigint | 8 | -9223372036854775808~9223372036854775807 | 0~18446744073709551615 |
注:无符号只需要在类型后加"unsigned",如:int unsigned
小数
浮点数
类型 | 占用空间(字节) |
---|---|
float | 4 |
double | 8 |
注:浮点数之间运算会有微小的误差,如果对精度要求特别高可以使用定点数。
定点数
类型 | 占用空间(字节) |
---|---|
decimal(m,d) | m+2 |
m表示精度,也就是"整数位+小数位"。
d表示标度,也就是小数位个数。
精度越高占用空间越大。
注:高精度向低精度转换时存在四舍五入现象。
位类型
类型 | 占用空间(位bit) |
---|---|
bit(m) | m |
当m=1时只能存储0和1。
m越大可以存的数越大。
注:bit类型相当于存储二进制,m为多少就占用多少个bit。
字符、文本
类型 | 占用空间(字符) | 长度范围 | 值的长度 | 备注 |
---|---|---|---|---|
char(m) | m | 0<=m<=255 | m | 定长 |
varchar(m) | m+1字节 | 0<=m<=65535 | m | 可变长度 |
tinytext | l+2字节 | 0<=l<=255 | l | 小文本,可变长度 |
text | l+2字节 | 0<=l<=65535 | l | 文本,可变长度 |
mediumtext | l+3字节 | 0<=l<=16777215 | l | 中等文本,可变长度 |
longtext | l+4字节 | 0<=l<=4294967295 | l | 大文本,可变长度 |
注:可变长度的类型会额外需要1到几个字节来记录占用空间的大小,这就是为什么占用空间要+1或+2...字节的原因。
枚举
类型 | 占用空间 | 长度 | 长度范围 |
---|---|---|---|
enum | 1或2个字节 | l | 1<=l<=65535 |
定义格式:enum('成员1','成员2','成员3','成员4')
注:包含枚举类型的字段插入数据时只能从定义的成员中选择一个。
集合类型 set
set类型和枚举类型很像,但是set类型可以在插入时选择多个成员的值插入。
成员数与占用空间的关系
成员范围 | 占用空间 (字节) |
---|---|
1<=l<=8 | 1 |
9<=l<=16 | 2 |
17<=l<=24 | 3 |
25<=l<=32 | 4 |
32<=l<=64 | 8 |
定义格式:set('成员1','成员2','成员3','成员4')
注:set类型可以存储多个成员,但是不会存储多个相同值的成员。
日期
类型 | 名称 | 字节 | 日期格式 | 最小值 | 最大值 | 备注 |
---|---|---|---|---|---|---|
year | 年 | 1 | YYYY | 1901 | 2155 | 年 |
time | 时间 | 3 | HH:MM:SS | -838:59:59 | 838:59:59 | 时、分、秒 |
date | 日期 | 3 | YYYY-MM-DD | 1000-01-01 | 9999-12-03 | 年、月、日 |
datetime | 日期时间 | 8 | YYYY-MM-DD HH:MM:SS | 1000-01-01 00:00:00 | 9999-12-31 23:59:59 | 年、月、日、时、分、秒 |
timestamp | 日期时间 | 4 | YYYY-MM-DD HH:MM:SS | 1970-01-01 00:00:00 UTC | 2038-01-19 03:14:07 UTC | 年、月、日、时、分、秒 |
注:timestamp不同时区显示的结果不同,而datetime会显示相同的结果。
二进制
类型 | 值的长度 | 占用空间(字节) | 备注 |
---|---|---|---|
binary(m) | 0<=m<=255 | m | 固定长度 |
varbinary(m) | 0<=m<=65535 | m+1 | 可变长度 |
tinyblob | 0<=l<=255 | l+1 | 可变长度,大二进制对象 |
blob | 0<=l<=65535(64KB) | l+2 | 可变长度,大二进制对象 |
mediumblob | 0<=l<=16777215(16MB) | l+3 | 可变长度,大二进制对象 |
longblob | 0<=l<=4294967295(4GB) | l+4 | 可变长度,大二进制对象 |
注:二进制一般用来存储二进制数据,比如图片、音频、视频等。
JSON类型
类型名就是"json"
可以将json类型当做普通字符串插入就行,只不过json是有特殊格式的字符串。
空间类型
空间类型用于表示空间位置信息,一般不使用,一些特定领域可能会使用到。
数据表操作
创建表
简单创建
使用"create table"关键字可以创建表,格式如下:
sql
create table [if not exists] 表名
(
字段1 数据类型,
字段2 数据类型,
...
字段n 数据类型
)
注:最后一个字段后是没有逗号的。
例如:创建一个student表,包含字段id、name、age。
sql
create table student
(
id int,
`name` varchar(10),
age int
)
注:如果字段名和关键字重复,必须使用着重号(`)引起来。
指定编码
数据表默认编码和数据库编码一样,也可以单独指定编码,使用"charset"关键字
sql
create table [if not exists] 表名
(
字段1 数据类型,
字段2 数据类型,
...
字段n 数据类型
)charset 字符编码
根据现有表创建新表
根据现有的表,使用select语句查询出的结果作为新表的内容,格式如下:
sql
create table 新表名
as
select语句
注:根据现有表创建新表后,查询出的数据也会存到新表中,如果没有数据就只会创建一个空表。
查看表
查看当前数据库下有哪些表
sql
show tables
查看表结构
使用"desc"可以查看表的结构,包括字段名、类型等,格式如下:
sql
desc 表名
例如:查看student表的结构
sql
desc student
查看创建表时的SQL语句
使用"show create table "可以查看创建表时的SQL语句
sql
show create table 表名
修改表字段
要修改表需要使用"alter table"关键字
添加一个字段
sql
alter table 要修改的表名
add 要添加的字段名 字段类型
修改字段的数据类型
sql
alter table 要修改的表名
modify 要修改的字段名 新的字段类型
重命名字段
sql
alter table 要修改的表名
change 旧的字段名 新的字段名 新字段的数据类型
删除一个字段
sql
alter table 要修改的表名
drop column 要删除的字段名
重命名表
修改表的名字
(1)第一种方式
sql
rename table 旧的表名
to 新的表名
(2)第二种方式
sql
alter table 旧的表名
rename to 新的表名
删除表
sql
drop table [if exists] 要删除的表名
清空表
将表的内容全部清除,保留表的结构。
sql
truncate table 要清空的表名
提交与回滚
提交commit
一旦执行commit提交数据,数据就被永久保存在数据库中,不可以回滚了。
数据库默认开启自动提交,如果需要设置手动提交可以使用如下命令设置关闭自动提交:
sql
set autocommit = false
回滚rollback
使用rollback会回滚到上次最近提交commit之后。
注:不可以回滚truncate table命令造成的结果。
表数据操作
运算符
算术运算符
符号 | 说明 |
---|---|
+ | 加 |
- | 减 |
* | 乘 |
/或div | 除 |
%或mod | 取余 |
注意:
- 在mysql中"+"号没有字符串连接的功能,比如100+'1'结果是101,并不是1001。
- 字符串参与运算会被当做0处理。null值参与运算结果为null。
- 整数值之间不能整除会得到小数值。
比较运算符
符号 | 说明 |
---|---|
> | 大于 |
< | 小于 |
= | 等于 |
<=> | 安全等于,拥有等于号的功能,除此之外还能比较null |
>= | 大于等于 |
<= | 小于等于 |
<>或!= | 不等于 |
注意:
- 字符串与其他类型比较会存在隐式转换,如果转换不成功看作0。
- 字符串之间比较按照ansi的比较规则。
- 除了安全等于,其他比较运算符有null参与比较时,结果为null。
一些特殊的比较运算符
符号 | 说明 |
---|---|
is null | 判断是否为空 |
is not null | 判断是否不为空 |
between...and... | 判断是否处于指定范围内,如id between 1 and 10,判断id是否大于1小于10 |
not between...and... | 判断是否不处于指定范围内,如id not between 1 and 10,判断id是否不处于大于1小于10的范围 |
in | 判断是否处于指定的某些值,如id in(1,3,4),判断id是否是1或2或3 |
not in | 判断是否不处于某些值,如id not in(1,3.5),判断id是否不是1或3或5 |
like | 专门用来判断字符串是否满足指定的格式,一般用于模糊查询,可以判断字符串以什么开头、以什么结尾、字符串中包含什么字符等 |
regexp | 使用正则表达式来判断字符串是否满足指定的格式。可用于模糊查询 |
一些用于比较的函数:
函数名 | 说明 |
---|---|
least | 选取一个最小值,如least(1,2.3)会返回1 |
greatest | 返回一个最大值,如greatest(1,2,3)会返回3 |
逻辑运算符
符号 | 说明 |
---|---|
and或&& | 逻辑与 |
or或|| | 逻辑或 |
not或! | 逻辑非 |
xor | 逻辑异或 |
注意:
位运算符
整数在内存中是以补码形式存储的,正数的补码形式和原码形式相同,而负数的补码形式和它的原码形式是不一样的。
符号 | 说明 |
---|---|
& | 与 |
| | 或 |
^ | 异或 |
~ | 按位取反(非) |
<< | 左移。格式:"a << b" 整数a向左移动b位" |
>> | 右移。格式:"a >> b" 整数a向右移动b位" |
添加
方式一:
sql
insert into 表名(表字段1,表字段2,表字段3,...表字段n) value(值1,值2,值3,...值n)
查入值的顺序要和括号中表字段的顺序一致。
方式二
sql
insert into 表名 value(值1,值2,值3,...值n)
插入值的顺序要和数据表中的字段顺序一致,并且数量也要一致,不指定插入哪些表字段相当于对所有表字段插入值。
查询
使用select语句可以查询数据,select语句类似一个输出语句
sql
select 1+1
多个值使用逗号分割
sql
select 1+1,2+2,3+3
取别名
可以为每一列取一个别名,中间用空格隔开或者使用"as"
sql
select 1+1 别名1, 2+2 别名2, 3+3 别名3
select 1+1 as 别名1, 2+2 as 别名2, 3+3 as 别名3
简单查询
使用select配合from关键字可以检索表中数据
sql
select 表字段1,表字段2 ...,表字段n
from 表名
如果要查询表中所有的字段,可以使用星号"*",表示表中所有字段
sql
select *
from 表名
带条件查询
where语句可以用来过滤数据,检索我们想要的数据
sql
select *
from 表名
where 过滤条件
例如只检索id列大于100小于200的列
sql
select *
from 表名
where id>100 and id<200
多个条件可以使用"and"、"or"等逻辑运算符连接
模糊查询
使用like进行模糊匹配
讲模糊匹配前需要了解两个符号
符号 | 说明 |
---|---|
% | 代表不确定个数的字符,'%a'表示以a结尾的字符串,也可以是a。'a%'表示以a开头的字符串,也可以是a。'%a%'表示字符串中包含有a,也可以是a |
_ | 代表一个不确定的字符 |
比如检索name列姓张的数据
sql
select *
from 表名
where `name` like '张%'
使用正则表达式
正则表达式regexp可以精确判断一个字符串是否满足指定的条件,语法格式如下
sql
select *
from 表名
where 表字段 regexp 正则表达式(字符串)
具体匹配条件的编写可以自行了解正则表达式。
排序
使用"order by"语句可以对检索出来的数据按照指定字段升序或降序排列,多个字段排序使用逗号分割
sql
select *
from 表名
[where 过滤条件]
order by 表字段 [desc|asc]
- desc:降序排列,不写排序规则默认就是desc
- asc:升序排列
"[ ]"内的内容可以省略
分页
使用"limit"语句可以对检索出的数据进行分页操作
sql
limit [offset,] rows
offset表示要跳过的行数,offset可省略,相当于0,rows表示要返回的行数。通常配合select语句使用
sql
SELECT 列名
FROM 表名
LIMIT N;
SELECT 列名
FROM 表名
LIMIT M, N;
聚合函数
聚合函数用于对数据进行计算和汇总,如下是一些常用的聚合函数
(1)count
统计表中行的数量或非NULL值的数量
sql
SELECT COUNT(*) FROM 表名; -- 统计表中的总行数
SELECT COUNT(列名) FROM 表名; -- 统计指定列非NULL值的数量
(2)sum
计算数值列的总和
sql
SELECT SUM(列名) FROM 表名; -- 计算指定列的总和
(3)avg
计算数值列的平均值
sql
SELECT AVG(列名) FROM 表名; -- 计算指定列的平均值
(4)max
获取数值列的最大值
sql
SELECT MAX(列名) FROM 表名; -- 获取指定列的最大值
(5)min
获取数值列的最小值
sql
SELECT MIN(列名) FROM 表名; -- 获取指定列的最小值
(6)group_concat
将列值连接为一个字符串
sql
SELECT GROUP_CONCAT(列名) FROM 表名; -- 将指定列的值连接为一个字符串
分组
group by
group by关键字用于将查询结果按照一个或多个列进行分组,然后对每个分组进行聚合运算
sql
SELECT 列名或表达式
FROM 表名
GROUP BY 列名或表达式;
- 分组列:GROUP BY子句中的"列名或表达式"指定要分组的列。可以是表的列名,也可以是计算得到的表达式。
- 聚合函数:通常与GROUP BY一起使用的是聚合函数(如SUM、AVG、COUNT等),用于对每个分组执行聚合计算。
- 分组顺序:查询结果按照GROUP BY子句中指定的列进行分组,并按照这些列的顺序进行排序。
- 多个列分组:可以使用逗号将多个列名或表达式组合在一起,实现多级分组。分组的优先级由列在GROUP BY子句中出现的顺序决定,先出现的列具有更高的优先级。
- 不分组列:除了GROUP BY子句中指定的列,SELECT子句可以包含其他非聚合列。这些列可以是分组列,也可以是不参与分组但需要显示在结果中的列。
having
在group by语句中筛选满足条件的分组
sql
SELECT 列名 FROM 表名 GROUP BY 列名 HAVING 条件; -- 对分组数据进行筛选
子查询
子查询是指一个查询语句嵌套在另一个查询语句中的查询结构。子查询可以用作主查询中的一部分,作为过滤条件、计算表达式、获取子集等。
子查询可以出现在SELECT、FROM、WHERE、HAVING、UPDATE或DELETE语句中的不同部分。
(1)WHERE子句中的子查询:子查询可以用于WHERE子句中,用来过滤满足特定条件的行。
sql
SELECT 列名
FROM 表名
WHERE 列名 IN (SELECT 列名 FROM 表名 WHERE 条件);
(2)FROM子句中的子查询:子查询可以用作FROM子句中的临时表,以便进行更复杂的查询操作。
sql
SELECT 列名
FROM (SELECT 列名 FROM 表名) [AS] 子查询表名;
(3)EXISTS子查询:EXISTS子查询用于检查子查询中是否存在满足给定条件的行,返回布尔值。
sql
SELECT 列名
FROM 表名
WHERE EXISTS (SELECT 列名 FROM 表名 WHERE 条件);
(4)子查询作为计算表达式:子查询可以作为计算表达式使用,返回一个值。
sql
SELECT 列名, (SELECT COUNT(*) FROM 表名 WHERE 条件) [AS] 计算结果 FROM 表名;
(5)子查询作为插入数据的来源:子查询可以作为INSERT语句的来源,将查询结果插入目标表中。
sql
INSERT INTO 目标表 (列名1, 列名2) SELECT 列名1, 列名2 FROM 源表 WHERE 条件;
通过使用子查询,我们可以在查询中利用嵌套查询结构和逻辑,从不同的角度处理和操作数据,实现更复杂的查询需求。
注:需要注意的是,子查询的性能可能不如联接(JOIN)等其他查询技术,因此在使用子查询时应注意查询的效率和性能优化。
多表连接
多表连接是将两个或多个表中的数据相关联的一种操作。通过连接,可以将具有相关数据的行组合在一起,以实现更复杂的查询和数据分析。
(1)使用where连接
sql
SELECT 列表达式
FROM 表1,表2
WHERE 表1.连接键 = 表2.连接键
(2)内连接
内连接返回两个表中连接键匹配的行,即两个表中连接键相等的行。
sql
SELECT 列表达式
FROM 表1
INNER JOIN 表2 ON 表1.连接键 = 表2.连接键;
(3)左连接
左连接返回左表中所有的行以及与右表中连接键匹配的行。如果右表中没有与左表中连接键匹配的行,则返回NULL值。
sql
SELECT 列表达式
FROM 表1
LEFT JOIN 表2 ON 表1.连接键 = 表2.连接键;
(4)右连接
右连接返回右表中所有的行以及与左表中连接键匹配的行。如果左表中没有与右表中连接键匹配的行,则返回NULL值。
sql
SELECT 列表达式
FROM 表1
RIGHT JOIN 表2 ON 表1.连接键 = 表2.连接键;
(5)全连接
全连接返回左表和右表中的所有行,如果某个表中没有与另一个表中连接键匹配的行,则返回NULL值。
sql
SELECT 列表达式
FROM 表1
FULL JOIN 表2 ON 表1.连接键 = 表2.连接键;
(6)自连接
自连接是指将表与其自身进行连接,用于处理包含与自身关联的数据的情况。
sql
SELECT 列列表达式
FROM 表 AS t1
JOIN 表 AS t2 ON t1.连接键 = t2.连接键;
合并查询结果集
可以使用union和union all关键字将多个结果集合并起来。多个需要合并的结果集需要满足如下条件才能合并:
- 每个查询的SELECT子句中列的数量和数据类型必须一致,即查询结果的列要匹配。
- 查询结果集的列的顺序应保持一致。
- 可以在每个SELECT语句中使用自己的WHERE、ORDER BY和GROUP BY子句,但UNION只应出现一次。也可以在UNION后添加额外的ORDER BY子句来对合并后的结果进行排序。
(1)union
union操作符可将多个查询的结果集合并为一个结果集,并且会对结果集进行去重,就是不会包含重复的行。
sql
SELECT 列名1, 列名2, ...
FROM 表名1
WHERE 条件1
UNION
SELECT 列名1, 列名2, ...
FROM 表名2
WHERE 条件2;
(2)union all
union all操作符可将多个查询的结果集合并为一个结果集,但是不会对结果集进行去重,所以合并的效率要比union高。
sql
SELECT 列名1, 列名2, ...
FROM 表名1
WHERE 条件1
UNION ALL
SELECT 列名1, 列名2, ...
FROM 表名2
WHERE 条件2;
删除
使用delete语句可以删除表中不需要的数据
sql
DELETE FROM 表
[WHERE 条件]
如果不加where条件会删除表中所有数据,加where会将符合条件的行删除掉。
修改
update语句用于修改表中的一行或多行数据。
sql
UPDATE 表名
SET 列名1 = 值1, 列名2 = 值2, ...
[WHERE 条件]
不加where条件会将表中所有设置的列设置为指定的值,加where只会修改符合条件的行。
常用函数
MySQL内置了许多函数供使用
日期和时间类型函数
获取当前日期
函数名 | 说明 |
---|---|
CURDATE() | 返回当前日期 |
CURTIME() | 返回当前时间 |
NOW() | 返回当前日期和时间 |
TIMESTAMP() | 返回当前时间戳 |
UNIX_TIMESTAMP() | 返回UNIX时间戳,表示从1970年1月1日以来的秒数 |
日期提取
函数名 | 说明 |
---|---|
DATE( date ) | 提取给定的日期date中的日期部分 |
TIME( date ) | 提取给定的日期date中的时间部分 |
YEAR( date ) | 提取年份 |
MONTH( date ) | 提取月份 |
DAY( date ) | 提取天数 |
WEEK( date ) | 返回给定的日期date是一年的第几周 |
DAYNAME( date ) | 返回给定的日期是星期几 返回值是一个字符串 |
HOUR( date ) | 提取小时 |
MINUTE( date ) | 提取分钟 |
SECOND( date ) | 提取秒数 |
日期格式化
DATE_FORMAT( date , format)
根据给定的日期格式化字符串将日期date格式化。常用日期符号如下:
- %Y:年
- %m:月
- %d:日
- %H:时
- %i:分
- %s:秒
日期运算函数
函数名 | 说明 |
---|---|
DATEDIFF( date1 , date2) | 计算两个日期之间的天数差值(date1-date2) |
DATE_ADD( date , INTERVAL num YEAR| MONTH| DAY| HOUR| MINUTE| SECOND) | 将日期增加指定的时间间隔。其中INTERVAL 是一个关键字,后面跟间隔数和时间单位 |
DATE_SUB( date , INTERVAL num YEAR| MONTH| DAY| HOUR| MINUTE| SECOND) | 将日期减去指定的时间间隔。其中INTERVAL 是一个关键字,后面跟间隔数和时间单位 |
字符处理函数
函数名 | 说明 |
---|---|
CONCAT(str1, str2 ...) | 用于拼接两个或多个字符串 |
SUBSTRING(str, pos,len) | 提取字符串的一部分(str-要提取的字符串。pos-起始位置,从1开始。len-提取的长度,可以省略,省略表示到字符串末尾) |
LEFT(str,len) | 返回字符串左边指定长度的子串 |
RIGHT(str,len) | 返回字符串右边指定长度的子串 |
LENGTH(str) 或 CHAR_LENGTH( str) | 返回字符串的长度 |
LOWER(str) | 将字符串转换为小写 |
UPPER(str) | 将字符串转换为大写 |
TRIM([{BOTH | LEADING | TRAILING} [remstr] FROM] str) | 去除字符串两端的空格或指定字符({BOTH | LEADING | TRAILING}-可选参数,用于指定从字符串开头和结尾删除字符的方式,如果省略,则默认为BOTH。remstr-要删除的字符集合。如果省略,则默认删除空格。str-要进行处理的字符串)例如:TRIM(',' FROM ' Hello, World! ') |
REPLACE(str, from_str, to_str) | 在字符串str中替换指定的子字符串from_str为新的子字符串to_str |
LOCATE(substr, str [, pos]) | 在一个字符串str中查找子字符串substr的第一次出现位置。(pos-可选参数,表示开始搜索的位置。如果省略,则默认从字符串的开头开始搜索。) |
LPAD(str, length, padstr) | 在字符串str左侧填充指定字符padstr,使字符串达到指定长度length |
RPAD(str, length, padstr) | 在字符串str右侧填充指定字符padstr,使字符串达到指定长度length |
INSTR(str, substr) | 查找一个字符串substr)在另一个字符串str中第一次出现的位置。如果找到了子串,则返回其在 str 中的位置(从 1 开始计数),如果未找到,则返回 0。 |
REVERSE(str) | 反转字符串 |
流程控制函数
函数名 | 说明 |
---|---|
IF(expr, true_value, false_value) | 根据指定条件返回不同的结果。(expr-条件表达式,可以是任何能够产生 TRUE 或 FALSE 结果的表达式。true_value-为 TRUE 时返回的值。false_value-为 FALSE 时返回的值)例如:SELECT IF(score >= 60, 'Pass', 'Fail') FROM students; |
IFNULL(value1, value2) | 如果value1不为NULL,则返回value1,否则返回value2 |
NULLIF(value1, value2) | 如果value1和value2相等,则返回NULL,否则返回value1 |
case函数
1.简单CASE表达式
sql
CASE case_expression
WHEN value1 THEN result1
WHEN value2 THEN result2
...
[ELSE else_result]
END
#case_expression-要进行比较的表达式
#value1、value2...-可能的取值
#result1、result2...-与每个取值对应的结果
#else_result-可选的,表示如果没有匹配到任何值,则返回的默认结果
举例
sql
SELECT
CASE department_id
WHEN 1 THEN 'HR'
WHEN 2 THEN 'IT'
WHEN 3 THEN 'Finance'
ELSE 'Other'
END AS department_name
FROM
employees;
2.搜索CASE表达式
sql
CASE
WHEN condition1 THEN result1
WHEN condition2 THEN result2
...
[ELSE else_result]
END
#condition1、condition2...-条件表达式,可以是任何能够产生 TRUE 或 FALSE 结果的表达式
#result1、result2...-与每个条件对应的结果
#else_result-可选的,表示如果没有匹配到任何条件,则返回的默认结果
举例
sql
SELECT
CASE
WHEN age < 18 THEN 'Child'
WHEN age BETWEEN 18 AND 64 THEN 'Adult'
ELSE 'Senior'
END AS age_group
FROM
person;
约束
约束实际上就是对表中数据做一些限制条件,用于确保数据库中数据完整性和一致性。
非空约束
非空约束用于确保表中特定列中的值不为空
如下是几种添加非空约束的方式:
方式一:建表时添加
sql
CREATE TABLE table_name (
column1 datatype NOT NULL,
column2 datatype,
...
);
#column1列被定义为NOT NULL
方式二:在已存在的表中添加
sql
ALTER TABLE table_name
MODIFY column_name datatype NOT NULL;
主键约束
主键约束用于唯一标识表中的每一行,并确保每个值都是唯一且不为空的。主键通常与一列或多列组合使用,它们必须满足以下条件:
- 每个表只能有一个主键。
- 主键列的值必须是唯一的,即不能重复(多列主键组合的值唯一)。
- 主键列的值不能为 NULL。
方式一:单列主键
sql
CREATE TABLE example (
id INT PRIMARY KEY,
name VARCHAR(50)
);
#设置id列为主键列
方式二:多列主键
sql
CREATE TABLE example (
id INT,
category_id INT,
PRIMARY KEY (id, category_id)
);
#设置id和category_id两列为主键,多列主键需要保证两个列组合的值唯一
方式三:修改表时添加
sql
#约束单个字段
alter table example add primary key(id);
#约束多个字段
alter table example add primary key(id,category_id);
删除主键
sql
ALTER TABLE example DROP PRIMARY KEY;
外键约束
外键(Foreign Key)用于建立表与表之间的关联关系。外键在一个表中创建,指向另一个表中的主键。
方式一:建表时添加
sql
CREATE TABLE orders (
order_id INT PRIMARY KEY,
product_id INT,
quantity INT,
CONSTRAINT fk_product FOREIGN KEY (product_id) REFERENCES products(product_id)
);
#orders表中的product_id列是一个外键,它引用了products表中的product_id列,
#这个外键约束的约束名为fk_product。
方式二:多列外键
sql
CREATE TABLE order_details (
order_id INT,
product_id INT,
quantity INT,
PRIMARY KEY (order_id, product_id),
CONSTRAINT fk_order FOREIGN KEY (order_id) REFERENCES orders(order_id),
CONSTRAINT fk_product FOREIGN KEY (product_id) REFERENCES products(product_id)
);
方式三:修改表时添加
sql
ALTER TABLE orders
ADD CONSTRAINT fk_product FOREIGN KEY (product_id) REFERENCES products(product_id);
删除外键
sql
ALTER TABLE orders DROP FOREIGN KEY fk_product;
外键关联策略
常见的外键类型有5种:
- CASCADE(级联):当父表中的记录被更新或删除时,将自动更新或删除子表中相应的记录。
- SET NULL(设为 NULL):当父表中的记录被删除或更新时,子表中相应的外键列将被设置为 NULL。
- RESTRICT(限制):当尝试删除或更新父表中的记录时,如果在子表中仍存在相关记录,则会阻止删除或更新操作。
- NO ACTION(无操作):与 RESTRICT 类似,当尝试删除或更新父表中的记录时,如果在子表中仍存在相关记录,则会阻止删除或更新操作。
- SET DEFAULT(设为默认值):当父表中的记录被删除或更新时,子表中相应的外键列将被设置为默认值。
MYSQL的默认策略就是更新和删除都是NO ACTION。如果想要切换其他策略可以在添加外键约束时指定其他策略,如下:
sql
FOREIGN KEY (parent_id) REFERENCES parent_table(id) ON DELETE CASCADE ON UPDATE CASCADE
FOREIGN KEY (parent_id) REFERENCES parent_table(id) ON DELETE SET NULL ON UPDATE SET NULL
FOREIGN KEY (parent_id) REFERENCES parent_table(id) ON DELETE RESTRICT ON UPDATE RESTRICT
FOREIGN KEY (parent_id) REFERENCES parent_table(id) ON DELETE NO ACTION ON UPDATE NO ACTION
FOREIGN KEY (parent_id) REFERENCES parent_table(id) ON DELETE SET DEFAULT ON UPDATE SET DEFAULT
#ON DELETE表示父键被删除时的操作
#ON UPDATE表示父键被修改时的操作
唯一约束
唯一约束用于确保某一列或一组列中的值是唯一的,不允许重复值。唯一约束类似于主键约束,但唯一约束允许空值(NULL),而主键约束不允许空值。
方式一:建表时添加
sql
CREATE TABLE <表名>(
<列名1> <类型1> [CONSTRAINT <约束名1> ]UNIQUE,
<列名2> <类型2> [CONSTRAINT <约束名2> ]UNIQUE,
...
<列名n> <类型n>
)
或
sql
CREATE TABLE <表名>(
<列名1> <类型1> ,
<列名2> <类型2> ,
...
<列名n> <类型n>,
[CONSTRAINT <约束名1> ]UNIQUE(<列名1>),
[CONSTRAINT <约束名2> ]UNIQUE(<列名2>)
)
方式二:修改表时添加
sql
ALTER TABLE <表名>
ADD [CONSTRAINT <约束名1> ]UNIQUE (<列名1>),
ADD [CONSTRAINT <约束名2> ]UNIQUE (<列名2>);
方式三:建表时添加多列联合唯一约束
sql
CREATE TABLE <表名>(
<列名1> <类型1> ,
<列名2> <类型2> ,
...
<列名n> <类型n>,
[CONSTRAINT <约束名> ]UNIQUE(<列名1>, <列名2>)
)
#<列名1>和<列名2>组合起来唯一
方式四:修改表时添加多列联合唯一约束
sql
ALTER TABLE <表名>
ADD [CONSTRAINT <约束名> ]UNIQUE (<列名1>, <列名2>);
删除唯一约束
sql
ALTER TABLE <表名>
DROP INDEX <约束名>;
自增约束
自增长约束用于指定一个列的值在每次插入新记录时自动增加,通常用于为表中的主键列生成唯一标识符。自增约束使用"AUTO_INCREMENT"关键字。
方式一:建表时添加
sql
CREATE TABLE <表名>(
<列名1> <类型1> AUTO_INCREMENT,
<列名2> <类型2> ,
...
<列名n> <类型n>
)
方式二:修改表时添加
sql
ALTER TABLE <表名>
MODIFY COLUMN <列名1> <类型1> AUTO_INCREMENT;
删除自增约束
sql
ALTER TABLE <表名>
MODIFY COLUMN <列名1> <类型1>;
检查约束
检查约束用于检查某个表中的字段值是否符合要求。
注意:MySQL5.7不支持CHECK约束,在MySQL8.0.16中开始支持CHECK约束
方式一:建表时添加
sql
CREATE TABLE <表名>(
<列名1> <类型1> [CONSTRAINT <约束名1> ]CHECK (<约束条件1>),
<列名2> <类型2> [CONSTRAINT <约束名2> ]CHECK (<约束条件2>),
...
<列名n> <类型n>
)
或
sql
CREATE TABLE <表名>(
<列名1> <类型1> ,
<列名2> <类型2> ,
...
<列名n> <类型n>,
[CONSTRAINT <约束名1> ]CHECK (<约束条件1>),
[CONSTRAINT <约束名2> ]CHECK (<约束条件2>)
)
举例
sql
CREATE TABLE employees (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50),
age INT,
CONSTRAINT check_age CHECK (age >= 18),
CONSTRAINT check_name CHECK (name IS NOT NULL)
);
#age字段的值必须大于等于18
#name字段的值不能为NULL
方式二:修改表时添加
sql
ALTER TABLE <表名>
ADD [CONSTRAINT <约束名> ]CHECK(<约束条件>);
删除检查约束
sql
ALTER TABLE <表名> DROP CHECK <约束名>;
默认值约束
默认值约束用于指定某一列中的默认值。
方式一:建表时添加
sql
CREATE TABLE <表名>(
<列1> <类型1> DEFAULT 0,
<列2> <类型2> DEFAULT '0',
...,
<列N> <类型N> DEFAULT 0,
)
方式二:修改表时添加
sql
ALTER TABLE <表名>
MODIFY <列1> <类型1> DEFAULT 0;
删除默认值约束
sql
ALTER TABLE <表名>
MODIFY <列1> <类型1> DEFAULT NULL;
视图
视图(View)是一种虚拟的表,它只包含查询语句定义的列和行数据。视图并不实际存储数据,而是根据查询定义的规则动态生成结果集。使用视图可以简化复杂的查询、隐藏表结构、提高数据安全性等。
创建视图
sql
CREATE VIEW <视图名> AS <SELECT语句>;
根据指定的SELECT语句创建一个视图,SELECT语句可以是一个简单查询也可以是一个复杂查询
删除视图
sql
DROP VIEW <视图名1> [ , <视图名2> ...];
修改视图
sql
ALTER VIEW <视图名> AS <SELECT语句>;
对视图进行操作(增、删、改、查)
视图创建成功后就可以像普通表一样使用关键字"INSERT、DELETE、UPDATE、SELECT"进行增删改查操作。操作视图实际操作的是基本表中的数据。
视图有一些限制条件(包括插入、更新和删除操作),这些限制主要是为了确保数据的一致性和安全性。以下是更新视图的一些主要限制:
- 不可直接更新包含聚合函数的视图: 如果视图中包含聚合函数(如 SUM、AVG、COUNT 等),则不能直接对这种视图进行更新操作。因为聚合函数会导致视图不可更新。
- 不可直接更新包含 DISTINCT 或 GROUP BY 的视图: 如果视图中包含 DISTINCT 或 GROUP BY 子句,也不能直接对这种视图进行更新操作,因为这些子句会使得视图不可更新。
- 不可直接更新虚拟列或计算列: 如果视图中包含虚拟列或计算列(例如,使用表达式生成的列),则不能直接对这些列进行更新操作。只能更新视图中的基础列(即对应于实际表的列)。
- 不可直接更新使用 UNION 的视图: 如果视图是使用 UNION 连接多个查询结果而生成的,则不能直接对这种视图进行更新操作。
- 必须包含基础表的主键或唯一键: 如果要对视图进行更新操作,视图所基于的基础表必须具有主键或唯一键。这是为了确保更新操作能够精确定位到要更新的记录。
- 不可直接更新视图中的虚拟列或别名列: 如果视图中包含虚拟列或别名列(例如,使用 AS 关键字创建的列别名),则不能直接对这些列进行更新操作。只能更新视图中的基础列。
- 不可更新用于连接的表: 如果视图是基于多个表连接而生成的,则不能直接对连接的表进行更新操作,只能对视图中的单个表进行更新。
sql
#增
INSERT INTO <视图名> [(字段名1, 字段名2, ...)] values|value (值1, 值2, ...);
#删
DELETE FROM <视图名> <where条件>
#改
UPDATE <视图名> SET <字段名1>=<值1>[,字段名2=值2,...] [<where条件>]
#查
SELECT <字段名1>[,字段名2,...] FROM<视图名> [<where条件>]
视图的操作和对表的操作语法是相同的
变量
系统变量
系统变量分为全局系统变量和会话系统变量,会话系统变量只对当前会话(连接)有效,全局系统变量对所有会话都生效。
查看所有全局或会话系统变量
sql
#全局
SHOW GLOBAL VARIABLES;
#会话
SHOW SESSION VARIABLES;
查看指定的全局或会话变量
sql
#全局
SELECT @@GLOBAL.<变量名>;
#会话
SELECT @@SESSION.<变量名>;
SELECT @@<变量名>;#这种方式也可查看会话变量
设置系统变量的值
sql
#全局
SET GLOBAL <变量名> = <值>;
SET @@GLOBAL.<变量名> = <值>;
#会话
SET SESSION <变量名> = <值>;
SET @@SESSION.<变量名> = <值>;
SET @@<变量名> = <值>;
SET <变量名> = <值>;
用户自定义变量
用户自定义变量通常以一个"@"开始,作用域只针对于当前会话有效。
创建变量和更新变量
sql
SET @<变量名>=<值>;
SET @<变量名>:=<值>;
SELECT @<变量名>:=<值>;
查看变量值
sql
SELECT @<变量名>;
删除变量
sql
#删除变量只需要给变量设置为NULL值就行
SET @<变量名>=NULL;
局部变量
局部一般只能在BEGIN...END语句内定义和使用,作用域也仅限于BEGIN...END语句内,通常在创建存储过程或存储函数中使用。
sql
...
BEGIN
#声明一个一个局部变量
DECLARE <变量名> <变量类型[INT | CHAR | VARCHAR...]> [DEFAULT <默认值>]
#为局部变量赋值
SET <变量名> = <变量值>
SET <变量名> := <变量值>
SELECT <字段名> INTO <变量名> FROM <表名>;
#其它操作
...
END
存储过程
存储过程是一组预先编译好的SQL语句集合,它们存储在数据库中并可以被重复调用。存储过程有助于简化复杂的数据库操作,并提高数据库的性能和安全性。
存储过程的创建
无参
语法
sql
DELIMITER $$
CREATE PROCEDURE <自定义的存储过程名称>()
BEGIN
# 其它操作语句
...
END$$
DELIMITER ;
其中DELIMITER用于改变语句分隔符,默认的分隔符是分号";",使用DELIMITER语句指定为其它符号为分隔符是为了避免在BEGIN...END语句内使用分号";"作为一个语句的结束时产生分号冲突,使用完自定义分隔符后,最好将分隔符恢复为默认的分号,以免影响后续的SQL语句解析。
举例
sql
DELIMITER $$
CREATE
PROCEDURE demo1()
-- 存储过程体
BEGIN
-- DECLARE声明 用来声明变量的
DECLARE de_name VARCHAR(10) DEFAULT '';
SET de_name = "jim";
-- 测试输出语句
SELECT de_name;
END$$
DELIMITER ;
有参
有参的存储过程可以在创建的过程中指定存储过程的参数。参数有三种类型:
- IN:接受调用者传入的数据(默认值)
- OUT:向调用者返回数据
- INOUT:即可以接受调用者传入的参数,也可以向调用者返回数据
sql
DELIMITER $$
CREATE PROCEDURE <自定义的存储过程名称>({IN|OUT|INOUT} <变量名1> <数据类型1> ,{IN|OUT|INOUT} <变量名2> <数据类型2> ,...)
BEGIN
# 其它操作语句
...
END$$
DELIMITER ;
举例
sql
#查询这个student表中指定sex有多少个人
DELIMITER $$
CREATE
PROCEDURE demo2(IN s_sex CHAR(1),OUT s_count INT)
-- 存储过程体
BEGIN
-- 把SQL中查询的结果通过INTO赋给变量
SELECT COUNT(*) INTO s_count FROM student WHERE sex= s_sex;
SELECT s_count;
END$$
DELIMITER ;
存储过程的调用
要调用编写好的存储过程使用"CALL"关键字
sql
CALL <存储过程名>(<传递的参数>);
举例
sql
#调用无参
CALL demo1();
#调用有参,@s_count是一个用户自定义变量
CALL demo2 ('男',@s_count);
查看创建的存储过程
sql
#显示所有存储过程
SHOW PROCEDURE STATUS
#显示特定数据库的存储过程
SHOW PROCEDURE STATUS WHERE db = <数据库名> AND NAME = <存储过程名>;
#显示存储过程的源码
SHOW CREATE PROCEDURE <存储过程名>;
删除存储过程
sql
DROP PROCEDURE <存储过程名>;
自定义函数
函数的创建
sql
DELIMITER $$
CREATE FUNCTION <函数名>([<参数列表>]) RETURNS <返回值类型> [<characteristics>]
BEGIN
#其它计算或SQL操作
...
RETURN <返回值>;
END$$
DELIMITER $$
- <参数列表>是一系列入参,格式为"<变量名> <数据类型>",可以没有入参。
- <返回值类型>表示函数返回的数据类型,可以是INT、CHAR、VARCHAR等
- <返回值>是函数内经过处理后实际返回的结果,要和<返回值类型>的类型一致
- 可选项,用于指定函数的特性。
函数特性说明:
- DETERMINISTIC:指定函数是否是确定性的,即对于相同的输入参数,函数是否始终返回相同的结果。使用 DETERMINISTIC 可以提高函数的性能,因为 MySQL 可以对其进行缓存。
- NOT DETERMINISTIC:与 DETERMINISTIC 相反,表示函数不是确定性的,对于相同的输入可能会返回不同的结果。
- READS SQL DATA:指定函数是否读取 SQL 数据,即是否包含对数据库表的读取操作。
- MODIFIES SQL DATA:指定函数是否修改 SQL 数据,即是否包含对数据库表的写入或更新操作。
- SQL SECURITY {DEFINER | INVOKER}:指定函数的 SQL 安全性,即在何种权限下执行函数。DEFINER 表示函数在定义者的权限下执行,而 INVOKER 表示函数在调用者的权限下执行。
- COMMENT 'string':为函数添加注释,描述函数的作用或其他相关信息。示例:COMMENT 'This function calculates the total sales.'
- LANGUAGE SQL:指定函数使用的语言是 SQL。
- NO SQL:指定函数不包含 SQL 语句,主要用于包装纯计算逻辑的函数。
- CONTAINS SQL:指定函数包含 SQL 语句。
举例
sql
#创建一个函数
DELIMITER $$ -- 定界符
-- 开始创建函数
CREATE FUNCTION user_main_fn(v_id INT) RETURNS VARCHAR(50)
BEGIN
-- 定义变量
DECLARE v_userName VARCHAR(50);
-- 给定义的变量赋值
SELECT f_userName INTO v_userName FROM t_user_main
WHERE f_userId = v_id;
-- 返回函数处理结果
RETURN v_userName;
END $$ -- 函数创建定界符
DELIMITER;
函数调用
sql
<函数名>([<实际参数>])
举例
sql
SELECT user_main_fn(1);
查看存储函数
(1)查看存储函数的状态信息
sql
SHOW FUNCTION STATUS [ LIKE <函数名> ];
(2)查看存储函数的创建信息
sql
SHOW CREATE FUNCTION <存储函数名> ;
(3)查看存储函数的信息
sql
SELECT * FROM information_schema.Routines
WHERE FOUTINE_NAME=<存储函数名> AND ROUTINE_TYPE='FUNCTION' \G
删除存储函数
sql
DROP FUNCTION [ IF EXISTS ] <函数名称> ;
流程控制
存储过程和存储函数都支持一系列的流程控制语句,这些语句可以用来控制程序的执行流程。
IF语句
sql
#语法一
IF <condition> THEN
<statements1>;
ELSE
<statements2>;
END IF;
#语法二
IF <condition1> THEN
<statements1>;
ELSEIF <condition2> THEN
<statements2>;
[ELSEIF <condition3> THEN
<statements3>;]
...
ELSE
<statementsN>;
END IF;
<condition>表示条件,是一个布尔类型得结果,THEN后面跟条件成立的语句,ELSE后跟条件不成立的语句。
举例
sql
CREATE PROCEDURE test1 ()
BEGIN
DECLARE id INT DEFAULT 1;
DECLARE class_name VARCHAR(30);
IF id=1 THEN
SET class_name='哇塞,Java大佬!';
ELSEIF id=2 THEN
SET class_name='原来是UI的啊';
ELSE
SET class_name='不用想了,肯定是产品小样';
END IF;
SELECT class_name;
END ;
CASE语句
CASE语句类似IF语句,根据给定的条件执行符合条件的语句。
sql
CASE
WHEN <condition1> THEN <statements1>
WHEN <condition2> THEN <statements2>
...
ELSE <default_statements>
END
LOOP循环
LOOP会重复执行语句列表,因此在循环时务必给出结束循环的条件,否则会出现死循环
sql
LOOP
<statements>;
IF <condition> THEN
LEAVE;
END IF;
END LOOP;
#LEAVE是一个跳转语句,用于从循环中跳出,类似java中的break。
举例
sql
CREATE PROCEDURE test_loop()
BEGIN
DECLARE counter INT DEFAULT 1;
LOOP
IF counter > 5 THEN
LEAVE;
END IF;
SELECT CONCAT('Counter is: ', counter);
SET counter = counter + 1;
END LOOP;
END;
WHILE循环
它会根据条件重复执行一组语句,直到条件不再满足为止。
sql
WHILE <condition> DO
<statements>;
END WHILE;
举例
它先执行一组语句,然后根据条件重复执行这组语句,直到条件为真为止。
sql
CREATE PROCEDURE test_while()
BEGIN
DECLARE counter INT DEFAULT 1;
WHILE counter <= 5 DO
SELECT CONCAT('Counter is: ', counter);
SET counter = counter + 1;
END WHILE;
END;
REPEAT循环
sql
REPEAT
<statements>;
UNTIL <condition>
END REPEAT;
举例
sql
CREATE PROCEDURE test_repeat()
BEGIN
DECLARE counter INT DEFAULT 1;
REPEAT
SELECT CONCAT('Counter is: ', counter);
SET counter = counter + 1;
UNTIL counter > 5
END REPEAT;
END;
跳转语句
- LEAVE:用于从循环中跳出,类似break
- ITERATE:用于在循环中跳到下一次迭代,类似continue
跳转语句通常可配合标签使用,用于跳出指定的循环,如下
sql
label: LOOP
IF <condition> THEN
LEAVE label;
END IF;
END LOOP label;
#定义了一个标签为label,在循环中使用跳转语句后跟标签名,表示跳出指定的标签。
#如果不定义标签表示跳出最近的循环
游标
游标(Cursor)是一种用于在存储过程或函数中遍历结果集的机制。它允许你在执行查询后逐行处理查询结果,类似于其他编程语言中的迭代器。使用游标有如下几个步骤:
- 声明游标
- 打开游标
- 使用游标
- 关闭游标
sql
#声明游标
DECLARE <游标名> CURSOR FOR <SELECT语句>;
#打开游标
OPEN <游标名>;
#使用游标(使用 FETCH 语句可以从游标中获取下一行数据,并将其存储在指定的变量中。可以将 FETCH 语句放在循环中,直到遍历完整个结果集)
FETCH <游标名> INTO <变量1>, <变量2>, ...;
#关闭游标
CLOSE <游标名>;
举例
sql
DELIMITER //
CREATE PROCEDURE example_cursor()
BEGIN
DECLARE done BOOLEAN DEFAULT FALSE;
DECLARE emp_id INT;
DECLARE emp_name VARCHAR(255);
-- 声明游标
DECLARE emp_cursor CURSOR FOR SELECT id, name FROM employees;
-- 打开游标
OPEN emp_cursor;
-- 循环遍历结果集
cursor_loop: LOOP
FETCH emp_cursor INTO emp_id, emp_name;
IF done THEN
LEAVE cursor_loop;
END IF;
-- 处理每一行数据,例如输出到控制台
SELECT CONCAT(emp_id, ': ', emp_name) AS employee_info;
END LOOP cursor_loop;
-- 关闭游标
CLOSE emp_cursor;
END//
DELIMITER ;
异常处理
异常处理是指在存储过程或函数中捕获和处理可能出现的错误或异常情况。MySQL 提供了一种使用 DECLARE ... HANDLER 语句来处理异常的机制。
sql
DECLARE <handler_type> HANDLER FOR <condition_value> <action_statement>;
#handler_type:异常处理程序类型,比如 CONTINUE, EXIT, UNDO等。CONTINUE表示遇到错误继续执行;EXIT表示遇到错误立马退出;UNDO表示遇到错误撤回之前的操作。
#condition_value:异常条件,可以是一个 SQLSTATE值或者一个MySQL错误码。
#condition_value格式:SQLSTATE <SQLSTATE值>或<MYSQL错误码>
#condition_value有几个特殊值可以使用:NOT FOUND-一般用于处理'SELECT INTO'中未找到结果的情况;SQLWARNING-捕获所有的SQL警告;SQLEXCEPTION-捕获所有的SQL异常。
#action_statement:在异常发生时要执行的语句或代码块。
一旦异常被捕获,MySQL 将执行与之关联的异常处理程序。可以根据不同的异常类型采取不同的处理措施,比如输出错误信息、记录日志、回滚事务等。
举例
sql
DELIMITER //
CREATE PROCEDURE example_procedure()
BEGIN
DECLARE division_by_zero CONDITION FOR SQLSTATE '22012';
DECLARE CONTINUE HANDLER FOR division_by_zero
BEGIN
SELECT 'Error: Division by zero!';
END;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SELECT 'Error: SQL exception occurred!';
END;
DECLARE EXIT HANDLER FOR NOT FOUND
BEGIN
SELECT 'Error: No data found!';
END;
-- 模拟除以零错误
DECLARE divisor INT DEFAULT 0;
DECLARE result FLOAT;
SET result = 10 / divisor;
-- 模拟SQL异常
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
SELECT * FROM non_existing_table;
-- 模拟未找到数据
DECLARE CONTINUE HANDLER FOR NOT FOUND BEGIN END;
SELECT * FROM existing_table WHERE id > 1000;
END//
DELIMITER ;
触发器
触发器是一种特殊类型的存储过程,它会在表上的特定事件(例如插入、更新、删除)发生时自动触发执行。触发器可以用于在数据库中实现各种复杂的业务逻辑和数据约束。
触发器发生错误,对表的操作将会取消。
创建触发器
sql
CREATE TRIGGER <触发器名> <触发器时间> <触发事件类型>
ON <表名>
FOR EACH ROW
BEGIN
-- 触发器的操作逻辑
END;
触发器时间
触发器时间用于指定触发器在表中数据被修改之前触发还是修改之后触发,有如下值可用:
- BEFORE:表中数据发生改变前触发
- AFTER:表中数据发生改变后触发
注:如果 before 触发器失败或者语句本身失败,将不执行 after 触发器(如果有的话)
触发事件类型
- INSERT:向表中新增数据时触发
- UPDATE:修改表中数据时触发
- DELETE:删除表中数据时触发
举例
sql
DELIMITER //
CREATE TRIGGER before_insert_trigger
BEFORE INSERT
ON users
FOR EACH ROW
BEGIN
-- 检查用户年龄是否合法
IF NEW.age < 18 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Error: Age must be at least 18!';
END IF;
END//
DELIMITER ;
#SIGNAL关键字用于生成用户定义的异常。45000表示通用的用户定义的异常。
常用关键字
NEW 和 OLD 关键字用于引用触发器事件中的行数据。它们的使用取决于触发器的类型以及事件类型。
- NEW:
INSERT 触发器:NEW 关键字引用即将插入的新行的数据。
UPDATE 触发器:NEW 关键字引用更新后的新行的数据。 - OLD:
UPDATE 触发器:OLD 关键字引用更新前的旧行的数据。
DELETE 触发器:OLD 关键字引用即将删除的旧行的数据。
使用方式为NEW/OLD.字段名
sql
CREATE TRIGGER after_employee_delete
AFTER DELETE ON employees
FOR EACH ROW
BEGIN
-- 记录即将删除的旧行数据
INSERT INTO deleted_employees_log (employee_id, name, salary)
VALUES (OLD.id, OLD.name, OLD.salary);
END;
查看创建的触发器
查看全部触发器
sql
SHOW TRIGGERS;
查看触发器的创建语句
sql
SHOW CREATE TRIGGER <触发器名字>;
删除触发器
sql
DROP TRIGGER <触发器名字>;