MySQL
安装
Arch Linux 二进制安装
下载 MySQL 对应系统的二进制包
创建 mysql 用户
# -M 不创建用户登录目录
useradd -M -s /sbin/nologin mysql
解压
xz -d mysql-8.3.0-linux-glibc2.28-x86_64.tar.xz
tar -xvf mysql-8.3.0-linux-glibc2.28-x86_64.tar
移动到 /usr/local/
目录下
mv mysql-8.3.0-linux-glibc2.28-x86_64 /usr/local/mysql
配置环境变量
export PATH="/usr/local/mysql/bin:$PATH"
初始化
# 会输出默认密码
./mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data
创建配置文件
sudo vim /etc/my.cnf
[mysqld]
user=mysql
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
socket=/usr/local/mysql/data/mysql.sock
log-error=/var/log/mysql/mysqld.log
pid-file=/usr/local/mysql/data/mysqld.pid
#pid-file=/run/mysqld/mysqld.pid
[client]
socket=/usr/local/mysql/data/mysql.sock
配置启动服务
# 创建服务
cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld
# 设置开机启动
systemctl enable mysqld
# 启动服务
systemctl start mysqld
配置
修改用户密码
alter user 'root'@localhost identified by '123456';
alter user 'root' identified by '123456'; # 默认的主机地址为 %
允许远程访问
use mysql;
update user set host = '%' where user = 'root';
flush privileges;
修改为 %
后无效
需要检查 my.cnf
文件中是否配置了 bind-address
为 127.0.0.1
,需要修改为 0.0.0.0
。
修改默认的字符编码
修改 my.ini
或者 my.cnf
配置文件:
character-set-server=utf8
collation-server=utf8_unicode_ci
登录数据库
执行 mysql
客户端命令
常用参数:
-u
: 登录的用户名-p
: 登陆使用的密码,不显示指定则在回车后显示-h
: 主机名,不指定默认为localhost
-P
: 端口号,不指定默认为3306
示例:
mysql -uroot -p test
使用 root 用户登录 test 数据库,会使用密码
SQL
数据库管理
显示所有数据库
show databases;
切换到指定数据库
use mysql; # 切换到 mysql 数据库
创建数据库
create database db_test; # 创建 db_test 数据库
create database db_tset default character set utf8mb4; # 创建一个是用 utf8mb4 字符集的数据库
查看当前数据库的默认编码
SHOW VARIABLES LIKE 'character_%';
中查看 character_set_database
的值。
查看创建数据库使用的编码
show create database db_test;
查看数据库使用的编码
status;
删除数据库
drop database db_test;
表管理
查看所有表
show tables;
显示表结构
use mysql;
desc user; # 显示 user 表的结构信息
describe user; # 显示 user 表的结构信息
Field | Type | Null | Key | Default | Extra |
---|---|---|---|---|---|
字段名 | 字段类型 | 是否允许为 null | 字段的约束 | 默认值 | 扩展属性 |
字段类型
整型:
TINYINT
: 8 位整数类型,支持的数据范围为:INTEGER
: 32 位整数类型,支持的数据范围为:BIGINT
: 64 位整数类型,支持的数据范围为:
浮点型:
FLOAT
: 32 位单精度浮点型DOUBLE
: 64 位双精度浮点型DECIMAL(M,D)
: 可变的小数值,通过M
指定整个字段支持的位数,通过 D 指定支持的小数位数,如 `DECIMAL(6, 4) 表示 2 位整数位 4 位小数位。- 使用
UNSINGED
使得不支持负数 - 使用
ZOREFILL
使用 0 填充整数位,默认小数位会自动使用 0 填充
- 使用
时间:
TIMESTAMP
: 时间戳 指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数,是一个 INT 值,最大支持到 2038 年。百度百科DATETIME
: 存储日期和时间(8 bytes),格式YYYY-MM-DD hh:mm:ss
DATE
: 存储日期(3bytes),格式:YYYY-MM-DD
TIME
: 存储时间(3bytes),格式:hh:mm:ss
字符串:
CHAR
: 定长字符串,支持即 0 ~ 255
个字节。VARCHAR
: 变长字符串,支持即 0 ~ 65535
个字节。TEXT
: 长文本数据,支持即 0 ~ 65535
个字节。BLOB
: 二进制形式的长文本数据,支持即 0 ~ 65535
个字节。
枚举和集合:
ENUM
: 支持存储单个预定义的值SET
: 支持存储多个预定义的值
约束
MySQL 的约束有 主键约束、外键约束、非 null 约束、唯一约束、check 约束以及自增约束。
一般来说自增约束其实约束什么,就是一个字段会自增,但是不会约束插入的值
check 约束是在 MySQL 8 中添加
主键约束
约束条件:
- 主键值需要唯一
- 一个表只能存在一个主键
- 主键字段不能为 null
创建主键约束:
- 在创建表是为字段添加
primary key
描述通过这种方式创建主键约束不能指定多个字段
sqlcreate table tb_test_pk( id int primary key, name varchar(11) );
- 通过使用
[constraint 约束名] primary key
为单个或者多个字段添加主键约束创建联合主键时,则表示联合的字段不能一起重复,如下面的表示 id 和 name 不能同时存在
sqlcreate table tb_test_mpk( id int, name varchar(11), constraint constraint_name primary key(id, name) );
不推荐操作
对已有表最佳主键:
alter table 表名 add primary key(字段列表);
alter table 表名 字段名 字段数据类型 primary key [其它约束];
删除主键约束:
alter table 表名 drop primary key;
删除主键前需要清除自增约束
自增约束
关键字 auto_increment
- 使用自增约束的字段必须是主键字段
- 只能存在一个自增约束字段
- MySQL 通过
information_schema
数据库的TABLES
表中的AUTO_INCREMENT
字段管理
创建自增约束:
只能在创建表是使用 auto_increment 关键字创建
查看表的下一个自增值:
show table status like '表名';
- sql
SELECT `AUTO_INCREMENT` FROM `information_schema`.`TABLES` WHERE `TABLE_SCHEMA` = '数据库名' AND `TABLE_NAME` = '表名';
设置自增值:
- 将下一个自增值设置为指定值:
alter table 表名 auto_incurment = 值;
- 重置自增值:
truncate table 表名
会将自增值设置为 1,并清空表数据
非 null 约束
关键字:not null
- 在 插入 和 更新 时不允许插入 null 值
- 为一个表添加 not null 约束时,原 null 值会转为类型默认值
查看相关操作:
唯一约束
关键字:unique
- 唯一约束值需要唯一
- 一个表可以存在 多个 唯一约束
- 唯一字段可以为 null
TIP
当一个表中不存在主键,但是存在非 null 的唯一索引,则 MySQL 会将其当作注意。
创建唯一约束:
- 在创建表是为字段添加
unique
描述sqlcreate table tb_test_unique( id int primary key, phone varchar(11) unique );
- 通过使用
[constraint 约束名] unique key(字段列表)
为单个或者多个字段添加唯一约束指定多个字段表示创建联合约束,不是表示每个字段唯一,而是组合在一起唯一
sqlcreate table tb_test_multi_unique( id int primary key, uid int, phone varchar(11), constraint unique key (uid, phone) );
添加唯一索引:
- 为单个字段添加:
alter table 表名 modify 字段名 字段类型 unique [其它约束];
- 为单个或者多个字段:
alter table tb_test_unique add unique key(字段列表);
删除唯一约束:
- 查询索引名称(Key_name 列)sql
show index from 表名;
- 删除索引sql
alter table 表名 drop index 索引名;
默认值约束
关键字:default
- 插入数据时,如果没有指定字段值,则使用默认值填充数据
创建默认值约束:
在创建表时指定
default 默认值
添加字段时指定:
alter table 表名 add 字段名 字段类型 default 默认值 其它约束;
修改时指定:
alter table 表名 modify 字段名 字段类型 default 默认值 其它约束
外键约束
外键约束又成参照完整性
阿里开发规范(【强制】 不得使用外键与级联,一切外键概念必须在应用层解决)
(概念解释)学生表中的 student_id 是主键,那么成绩表中的 student_id 则为外键。 如果更新学生表中的 student_id,同时触发成绩表中的 student_id 更新,即为级联更新。
- 外键与级联更新适用于单机低并发,不适合分布式、高并发集群;
- 级联更新是强阻塞,存在数据库更新风暴的风险;
- 外键影响数据库的插入速度。
定义外键约束
-- 在表级上使用
FOREIGN KEY (<属性>) REFERENCES <表名>(<属性>)
-- 可设置更新和删除操作
FOREIGN KEY (<属性>) REFERENCES <表名>(<属性>) ON UPDATE CASCADE ON DELETE CASCADE
-- 当更新或删除被参照表时,参照表也更新
-- 除了 CASCADE 还有 NO ACTION, SET NULL
-- NO ACTION 为默认,直接拒绝操作
- 参照属性必须唯一(主键约束、唯一约束)
- 具有外键约束的表不能插入被参照表不存在的数据
- 没有设置更新删除操作的外键约束,不能直接更新删除被参照表
示例
-- 定义学生表
create table tb_student
(
id int primary key auto_increment comment '学生 ID',
name varchar(10) comment '学生姓名'
);
-- 定义成绩表
create table tb_score
(
student_id int comment '成绩 ID',
score tinyint comment '成绩',
foreign key (student_id) references tb_student (id)
);
-- 往学生表中插入数据
insert into tb_student(name)
values ('张三'),
('李四'),
('王五');
-- 往成绩表中插入存在的 student_id 数据
insert into tb_score(student_id, score)
values (1, 60),
(2, 90),
(3, 100);
-- 往成绩表中插入不存在的 student_id 数据
insert into tb_score(student_id, score)
values (4, 100);
-- 会出现如下错误
-- [1452] Cannot add or update a child row: a foreign key constraint fails (`db_test`.`tb_score`, CONSTRAINT `tb_score_ibfk_1` FOREIGN KEY (`student_id`) REFERENCES `tb_student` (`id`))
-- 直接删除学生表数据
delete from tb_student where id = 3;
-- 会出现如下错误
-- [1451] Cannot delete or update a parent row: a foreign key constraint fails (`db_test`.`tb_score`, CONSTRAINT `tb_score_ibfk_1` FOREIGN KEY (`student_id`) REFERENCES `tb_student` (`id`))
-- 先删除成绩表(参照表)的数据才能删除学生表(被参照表)的数据
delete from tb_score where student_id = 3;
delete from tb_student where id = 3;
-- 修改为级联更新和删除置 null
-- 1. 查找外键约束的名称 2. 删除外键约束 3. 添加外键约束
show create table tb_score;
alter table tb_score drop foreign key tb_score_ibfk_1;
alter table tb_score add foreign key (student_id) references tb_student(id) on update cascade on delete set null;
-- 通过上面的修改,更新参照表的数据还是需要包装被参照表的数据存在
-- 但是更新被参照表的数据则可以是的参照表的数据级联更新
select * from tb_student; -- 应该只存在 1,2 两条数据
select * from tb_score; -- 应该也是存在 1,2 两条数据
update tb_student set id = 3 where id = 2;
select * from tb_score; -- 应该只存在 1,3 两条数据
-- 上面的修改还设置了删除时的操作,允许在参数被参照表的设置参照表的值为 null
delete from tb_student where id = 1;
select * from tb_score; -- 应该也是存在 null,3 两条数据
check 约束
对插入数据进行检查
MySQL 8 才支持 check 约束
列级定义:
check (条件)
表级定义:
check (条件)
创建表
create table [表名] (
字段名 字段类型 [primary key] [auto_incrment] [not null] [default 默认值] [comment '字段说明'][,]
...
);
- 使用
primary key
则必须是not null
的,即不能显示指定null
- 使用
auto_increment
则必须是primary key
删除表
drop if exists table [表名];
修改表结构
# 新增字段
alter table 表名 add [column] 字段名 字段类型 [其它约束] [FIRST | AFTER 在哪一列后];
# 修改字段名称和字段类型
alter table change 字段名 新字段名 字段类型 [其它约束] [FIRST | AFTER 在哪一列后];
# 修改字段类型和约束
alter table 表名 modify 字段名 字段类型 [其它约束] [FIRST | AFTER 在哪一列后];
# 删除字段
alter table drop 字段名;
CHANGE 与 MODIFY 的区别
- CHANGE 不论是否修改字段名都需要传入新的字段名。
- MODIFY 不能修改字段名
增删改查
示例表数据结构
create table tb_test(
id int primary key auto_increment,
name varchar(10),
gender enum('男', '女'),
age int
);
插入数据
语法:
insert [ignore] [into] tb_test[(字段名1[,字段名2]...) value (值1[,值2]...);
insert [ignore] [into] tb_test[(字段名1[,字段名2]...) values (值1[,值2]...)[,(值1[,值2]...)]...];
可以不写
into
关键字(暂时没找到写于不写的区别)
ingore
表示忽略插入时的主键冲突,不插入数据,但是不报错,只显示警告
insert tb_test(name, gender, age)
values ('张三', 1, 20), ('李四', '女', 24); # 1 表示定义枚举时的第一个
insert into tb_test(id, name, gender, age)
values (3, '王', 2, 50);
查询数据
单表查询语法:select [distinct] 字段列表 from 表名 [where 条件] [GROUP BY (字段列表)] [ORDER BY 列名 [ASC | DESC]] [LIMIT number [[OFFSET|,] number]];
LIMIT m, n
中 m 表示偏移量,n 表示取的行数,等价于LIMIT n OFFSET m
distinct
表示去重,去除查询结果中重复的数据行(记录)
select * from tb_test; # 查询所有数据
select name, age from tb_test; # 查询部分字段数据
where 子句
where
用于设置查询数据的过滤条件。
- 支持比较值的大小关系:
>
、>=
、<
、<=
、!=
- 区间匹配:
between value1 and value2
,即[value1, value2]
- 支持逻辑关键字:
and
、or
、not
- 集合关系:
in
、not in
- 模糊查询:
like
,eg:字段 like '_值%'
(_
匹配任意一个字符,%
匹配领个或者多个任意字符),一般推荐使用右模糊查询即like '值%'
order 子句
order
子句用来设置数据的排序方式,通过哪些字段进行排序
ASC
: 是升序排序DESC
: 是降序排序
group by 子句
对查询数据进行分组,使用 group by
的查询语句, 则 select
的字段只能存在在 group by
的字段中, 或者使用聚合函数计算分组数据的值。
子查询(又叫嵌套查询)
查询语句中的条件也是一个查询语句
子查询 的查询条件 不依赖父查询 的查询称为 不相关子查询
子查询 的查询条件 依赖父查询 的查询结果称为 相关子查询,整个查询语句称为相关嵌套查询
示例
-- 定义表和插入数据
-- 建立一个学生表
CREATE TABLE Student
(
Sno CHAR(9) PRIMARY KEY, -- 列级完整性约束条件,Sno 是主码
Sname CHAR(20) UNIQUE, -- Sname 取唯一值
Ssex CHAR(2),
Sage SMALLINT,
Sdept CHAR(20)
);
-- 建立一个课程表
CREATE TABLE Course
(
Cno CHAR(4) PRIMARY KEY, -- 列级完整性约束条件,Cno 是主码
Cname CHAR(40) NOT NULL, -- 列级完整性约束条件,Cname 不能取空值
Cpno CHAR(4),
Ccredit SMALLINT,
FOREIGN KEY (Cpno) REFERENCES Course (Cno) -- 表级完整性约束条件,Cpno 是外码,被参照表是 Course,被参照列是 Cno
);
-- 建立一个学生选课表
CREATE TABLE SC
(
Sno CHAR(9),
Cno CHAR(4),
Grade SMALLINT,
FOREIGN KEY (Sno) REFERENCES Student (Sno), -- 表级完整性约束条件,Sno 是外码,被参照表是 Student,被参照列是 Sno
FOREIGN KEY (Cno) REFERENCES Course (Cno) -- 表级完整性约束条件,Cno 是外码,被参照表是 Course,被参照列是 Cno
);
INSERT INTO Student
VALUES ('201215121', '李勇', '男', 20, 'CS'),
('201215122', '刘晨', '女', 19, 'CS'),
('201215123', '王敏', '女', 18, 'MA'),
('201215124', '张立', '男', 19, 'IS');
INSERT INTO Course
VALUES ('2', '数学', null, 2),
('6', '数据处理', null, 2),
('7', 'PASCAL 语言', 6, 4),
('4', '操作系统', 6, 3),
('5', '数据结构', 7, 4),
('1', '数据库', 5, 4),
('3', '信息系统', 1, 4);
INSERT INTO SC
VALUES ('201215121', '1', 92),
('201215121', '2', 85),
('201215121', '3', 88),
('201215122', '2', 90),
('201215122', '3', 80);
-- === 不相关子查询 ===
-- 查询与刘晨在同一个系的学生
SELECT *
FROM Student
WHERE Sdept IN (SELECT Sdept
FROM Student
WHERE Sname = '刘晨');
-- 查询了选修了“信息系统”的学生序号和姓名
SELECT Sno, Sname
FROM Student
WHERE Sno IN (SELECT Sno
FROM SC
WHERE Cno IN (SELECT Cno
FROM Course
WHERE Cname = '信息系统'));
-- === 相关子查询 ===
-- 找出每个选项超过他自己选修课程平均成绩的课程号
SELECT Sno, Cno
FROM SC AS o
WHERE Grade > (SELECT AVG(Grade)
FROM SC i
WHERE o.Sno = i.Sno);
-- === 带有 ANY(SOME) 或 ALL 谓词的子查询
-- 查询非计算机科学系中比计算机科学系任意一个学生年龄小的学生姓名和年龄
SELECT Sname, Sage
FROM Student
WHERE Sdept != 'CS'
AND Sage < ANY (SELECT Sage
FROM Student
WHERE Sdept = 'CS');
-- 查询非计算机科学系中比计算机科学系所有学生年龄小的学生姓名和年龄
SELECT Sname, Sage
FROM Student
WHERE Sdept != 'CS'
AND Sage < ALL (SELECT Sage
FROM Student
WHERE Sdept = 'CS');
-- === 带有 EXISTS 谓词的子查询
-- 查询所有选修了 1 号课程的学生姓名
SELECT Sname
FROM Student
WHERE EXISTS (SELECT *
FROM SC
WHERE SC.Sno = Student.Sno
AND Cno = '1');
-- 查询所有没有选修了 1 号课程的学生姓名
SELECT Sname
FROM Student
WHERE NOT EXISTS (SELECT *
FROM SC
WHERE SC.Sno = Student.Sno
AND Cno = '1');
多表查询
- 笛卡尔积(隐式内连接):
select ... from 表一,表二
; - 内连接:
select ... from 表一 [inner] join 表二 on 条件
- 全外连接:保留自然连接的悬浮元组(共有属性值没有匹配的值的元组)
MySQL 中没有直接的全外连接
- 左外连接:只保留右侧表属性组为空的悬浮元组
SELECT ... FROM table1 LEFT JOIN table2 ON table1.common_field = table2.common_field;
- 右外连接:只保留左侧表属性组为空的悬浮元组
SELECT ... FROM table1 RIGHT JOIN table2 ON table1.common_field = table2.common_field;
示例
使用的数据和子查询一致
-- 使用自然连接查询学生选课情况
SELECT S.Sno, Sname, Ssex, Sdept, Cno, Grade
FROM Student AS S, SC
WHERE S.Sno = SC.Sno;
-- 查询课程的间接先行课
SELECT F.Cno, S.Cpno
FROM Course AS F, Course AS S
WHERE F.Cpno = S.Cno AND S.Cpno IS NOT NULL;
-- 查询学生的学生信息和其选课信息
SELECT S.Sno, Sname, Ssex, Sage, Sdept, Cno, Grade
FROM Student S LEFT OUTER JOIN SC ON (S.Sno = SC.Sno);
-- 查询每个学生的学号、姓名、选修课程名、成绩
SELECT S.Sno, Sname, Cname, Grade
FROM Student S, Course, SC
WHERE S.Sno = SC.Sno AND Course.Cno = SC.Cno;
更新数据
格式:`UPDATE 表名 SET 字段名=值[,字段名=值]... [WHERE 条件];
update tb_test set name = '王五' where id = 3;
DANGER
更新数据时需要检查是否使用了有效的 WHERE 表达式,避免更新整个数据库。
删除数据
格式:`DELETE FROM 表名 [WHERE 条件];
delete from tb_test where id = 3;
DANGER
删除数据时需要检查是否使用了有效的 WHERE 表达式,避免删除整个数据库。
常用函数
一般情况下聚合函数不能在 where 子句中使用,因为 where 用于过滤视图中的数据,在聚合和分组操作之前处理。
SUM
: 聚合函数,总和AVG
: 聚合函数,平均值MAX
: 聚合函数,最大值MIN
: 聚合函数,最小值FLOOR
: 向下取整CEIL
: 向上取整RAND
: 生成 [0,1) 的随机值CONCAT
: 拼接多个值SELECT CONCAT('value = ', 1);
显示警告信息
show warnings;
函数和存储过程
定义语法
CREATE
[DEFINER = user]
PROCEDURE [IF NOT EXISTS] sp_name ([proc_parameter[,...]])
[characteristic ...] routine_body
CREATE
[DEFINER = user]
FUNCTION [IF NOT EXISTS] sp_name ([func_parameter[,...]])
RETURNS type
[characteristic ...] routine_body
proc_parameter:
[ IN | OUT | INOUT ] param_name type
func_parameter:
param_name type
param_name:
参数名称
type:
任何有效的 MySQL 数据类型
characteristic: {
COMMENT 'string'
| LANGUAGE SQL
| [NOT] DETERMINISTIC
| { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
}
routine_body:
存储过程或函数的主体部分,包含 SQL 代码逻辑
对公共部分进行解释:
[DEFINER = user]
: 指定存储过程或者函数的创建者(默认是当前用户),可用来和SQL SECURITY
特征配合。characteristic
: 存储过程或函数特征。COMMENT 'string'
: 注释,描述存储过程或函数的作用。LANGUAGE SQL
: 指定是用 SQL 语言[NOT] DETERMINISTIC
: 指定函数的确定性,如果是DETERMINISTIC
则表示是确定的,相同的输入会得到相同的输出结果。默认是NOT DETERMINISTIC
。{ CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
: SQL 行为。CONTAINS SQL
: 默认行为,表示存储过程或函数包含 SQL 语句,但这些语句不会读取或修改数据库数据NO SQL
: 表示存储过程或函数不包含任何 SQL 语句。它完全是逻辑运算或调用其他不包含 SQL 的过程或函数。READS SQL DATA
: 表示存储过程或函数读取数据库数据,但不修改数据。这意味着它可以执行 SELECT 语句或调用仅读取数据的其他存储过程或函数。MONIFIES SQL DATA
: 表示存储过程或函数读取并修改数据库数据。这意味着它可以执行INSERT
、UPDATE
、DELETE
等修改数据的 SQL 操作。
SQL SECURITY { DEFINER | INVOKER }
: 安全特征。DEFINER
: 存储过程或函数以DEFINER
指定的用户权限执行,而不是调用者的权限。INVOKER
: 存储过程或函数以调用者的权限执行。
routine_body
可是简单的 SQL 语句也可以是复合语句,可以阅读复合语句的语法的官方文档,也可以查看复合语句部分。
复合语句
在 MySQL 客户端需要修改分隔符
DELIMITER // -- 修改分隔符为两个斜杠
BEGIN
SELECT NOW();
END // -- MYSQL 读取到两个斜杠后就会正常提交
DELIMITER ; -- 设置回分号
语法:
[begin_label:] BEGIN
[statement_list]
END [end_label]
statement_list
为要执行的语句列表,可以为空,并且可以嵌套复合语句。begin_label
和end_label
用于定义标签。可通过ITERATE
和LEAVE
引用这个标签。- 定义规则:
- 开始标签后面要紧跟一个冒号
:
。 - 可以只有开始标签没有结束标签,但是有结束标签一定要有开始标签。
- 同一嵌套级的标签必须不同。
- 标签不能超过 16 个字符。
- 开始标签后面要紧跟一个冒号
ITERATE
: 结束标签剩下语句,如果满足条件继续迭代。LEAVE
: 离开标签块。
- 定义规则:
声明语句(DECLARE Statement)
注意
- 声明语句只能在
BEGIN...END
块中使用。 - 声明语句必须位于任何其他语句之前。
- 声明必须遵循如下顺序:
变量(Variable)和条件(Condition)
->游标(Cursors)
->处理程序(Handler)
变量
语法:
DECLARE var_name [, var_name] ... type [DEFAULT value]
修改变量的方法:
- 使用 SET 语句。
- 使用
SELECT ... INTO
SET 语句
SET variable = expr [, variable = expr] ...
variable: {
user_var_name
| param_name
| local_var_name
| {GLOBAL | @@GLOBAL.} system_var_name
| {PERSIST | @@PERSIST.} system_var_name
| {PERSIST_ONLY | @@PERSIST_ONLY.} system_var_name
| [SESSION | @@SESSION. | @@] system_var_name
}
- 用户定义变量:使用
@var_name
格式定义的变量会保存在会话上下文中。无须使用DECLARE
进行声明。 - 参数和局部变量:使用
var_name
格式。必须声明或者在参数列表中,才能使用 SET 语句。 - 系统变量
- 使用
@@var_name
或者GLOBAL var_name
格式进行全局赋值,重启失效。 - 使用
@@SESSION.var_name
或者SESSION var_name
格式修改会话系统变量,在会话内有效。 - 使用
@@LOCAL.var_name
或者LOCAL var_name
格式修改系统变量,只在存储过程、触发器中临时起效。 - 使用
@@PERSIST.var_name
或者PERSIST var_name
格式修改系统变量,会持久化保存在配置文件中。
- 使用
流程控制语句
MySQL 不支持 FOR 循环
CASE Statement
构建复杂的分支结构。
CASE case_value
WHEN when_value THEN statement_list
[WHEN when_value THEN statement_list] ...
[ELSE statement_list]
END CASE
--
CASE
WHEN search_condition THEN statement_list
[WHEN search_condition THEN statement_list] ...
[ELSE statement_list]
END CASE
IF Statement
条件语句。
IF search_condition THEN statement_list
[ELSEIF search_condition THEN statement_list] ...
[ELSE statement_list]
END IF
ITERATE Statement
ITERATE
只能出现在 LOOP
、REPEAT
和 WHILE
语句中。
ITERATE
的意思是“再次开始循环”,即其它编程语言的 continue
。
LEAVE Statement
语句用于退出具有给定标签的流控制结构。如果标签是最外层存储的程序块,则 LEAVE
退出程序。
LEAVE
可以在 BEGIN ... END
或循环结构(LOOP
、REPEAT
、WHILE
)中使用。
LOOP Statement
无限循环结构,需要使用 LEAVE
进行退出循环。所有一般需要和 IF
或者 CASE
语句配合。
[begin_label:] LOOP
statement_list
END LOOP [end_label]
REPEAT Statement
执行循环体的的语句,执行完成后判断条件,如果为 true
则结束循环。
DO WHILE
条件为 假 时结束。DO UNTIL
条件为 真 时结束。
[begin_label:] REPEAT
statement_list
UNTIL search_condition
END REPEAT [end_label]
RETURN Statement
退出函数并返回数据,只在函数中使用,其它需要使用 LEAVE
RETURN expr
WHILE Statement
只要条件为真就一直执行循环体的语句。
[begin_label:] WHILE search_condition DO
statement_list
END WHILE [end_label]
存储过程
存储过程是一组 预编译的 SQL 语句集合,可接受 参数、执行逻辑 和 返回结果。 可简化复杂的数据库操作、提高性能和安全性。
参数类型:
IN
: (只读、默认),存储过程内部对 IN 参数的修改不会影响调用者传入的值。IN 参数是默认参数类型。OUT
: (只写),存储过程内部对 OUT 参数赋值会覆盖其初始值。调用者在调用存储过程时必须提供一个变量来接收 OUT 参数的值。INOUT
: (读写),存储过程内部对 INOUT 参数的修改会影响调用者传入的值。调用者在调用存储过程时必须提供一个变量来传递 INOUT 参数的初始值,并接收存储过程返回的修改后的值。
函数
MySQL 函数是一段可重复使用的 SQL 代码,接受参数并返回一个值,函数可以用于计算、转换数据等操作,可以在 SQL 语句中 直接调用。
创建一个计算两数之和的函数并使用:
CREATE FUNCTION AddValue(VALUE1 INT, VALUE2 INT)
RETURNS int
BEGIN
DECLARE RES INT;
SET RES = VALUE1 + VALUE2;
RETURN RES;
END;
SELECT AddValue(1, 2);