
- 🏠 博客主页:小谢同学的小破站
- ✍️ 本文由 小谢同学的小破站 原创,首发于 CSDN💻
- ☕ Java学习专栏:java
- 📗 MySQL专栏:MySQL
- 🧩 数据结构与算法:Java 数据结构与算法
- 🌐C语言专栏: C语言
- 👍 欢迎点赞👍 收藏⭐ 留言📝,发现错误欢迎指正!
- ✨ 脚踏实地,持续深耕,奔赴自己的目标✨
-- -- -- -- -- 💫分割线💫----------
MySQL 进阶笔记:用户 / 会话 / 全局 / 局部变量 + CASE 分支语法:
- [1. 四大变量](#1. 四大变量)
- [1.1 系统变量](#1.1 系统变量)
- [1.2 用户自定义变量](#1.2 用户自定义变量)
- [1.3 局部变量](#1.3 局部变量)
- [2. SQL编程](#2. SQL编程)
- [2.1 IF语句](#2.1 IF语句)
- [2.2 CASE语句](#2.2 CASE语句)
前言:
这里是小谢同学的 MySQL 学习记录,整理全局、会话、局部变量以及 SQL 编程语法。笔记用于自我复盘巩固,有错误欢迎大家指出,专栏还有 Java、网络、C 语言系列笔记欢迎翻阅
1. 四大变量
| 变量类型 | 声明方式 | 作用域 | 生命周期 | 查看 |
|---|---|---|---|---|
| 系统变量 | 系统定义好的 | 全局/会话 | 服务器运行期间 | @@global.xxx / @@session.xxx |
| 用户自定义变量 | @var |
当前会话 | 会话断开即销毁 | @var |
| 局部变量 | DECLARE |
存储过程 / 函数内部 | 代码块结束即销毁 | 直接用变量名 |
1.1 系统变量
系统变量又分为:全局变量与会话变量
全局变量(Global):对所有新的连接都生效,修改后已经存在的连接不受影响
会话变量(Session):只对当前连接有效,断开连接需要重新部署
例如:大楼统一规定上班时长、门禁规则,只要进这个大楼,所有人都要遵守这套规则。
- 修改global全局变量:可以形象的理解为修改的是公司制度
- 新进来的员工才会收到新规则的约束
- 而老员工是已经存在的会话不会立即生效
- 当MySQL重新启动之后,全局变量会默认恢复(相当于大楼断电重启,临时修改的制度表作废)
- 会话变量(session) = 每个员工自己的个人专属设置
- 每个客户端连接,相当于一个独立员工。
- 例如员工在擦自己桌子时不会影响到别人,喝水同理
- 修改会话变量只会对当前一对话生效,别的连接完全不受影响
- 连接断开会直接销毁,设置全部消失`
设置与查看系统变量:
sql
-- 查看所有系统变量
SHOW GLOBAL VARIABLES;
show SESSION VARIABLES;
-- 查看指定的系统变量采用模糊查询的形式
select @@GLOBAL.系统变量名;
select @@SESSION.系统变量名;
-- @@ 不带前缀默认查 session 级
SELECT @@autocommit;
-- 查询auto开头的全局变量与查看以char结尾的会话系统变量
SHOW GLOBAL VARIABLES LIKE 'auto%';
SHOW SESSION VARIABLES LIKE 'char%';
-- 修改(会话级别,当前会话生效)
SET SESSION autocommit = 0;
-- 修改全局
SET GLOBAL autocommit = 0;
1.2 用户自定义变量
用户自定义变量是由用户自己定义 的,会话级别的变量,使用@前缀作为标识 ,相当于当前会话的临时记事本;
复制方式分为两种:
- 一种为
=进行赋值, - 或者
:=进行赋值(更推荐使用:=这样更加明确是赋值操作而不是判断相等)
使用SET进行赋值
sql
-- 方式一:
SET @name := '张三';
SET @age = 18;
select @name,@age;
使用SELECT进行赋值
sql
-- 方式二
select @count:= COUNT(*) from student;
select @count;
不需要声明变量的类型,赋值时会自行进行判断
没有赋值的变量值为null
作用域: 只在当前会话中有效
1.3 局部变量
局部变量这个概念和我们之前学习的C语言和Java中类似,只不过MySQL中局部变量是存在于存储过程或者函数内部声明的变量,内部使用DECLARE来标识
局部变量的使用与赋值:
sql
DELIMITER //
CREATE PROCEDURE p1()
BEGIN
-- 声明
DECLARE x INT DEFAULT 0;
DECLARE name varchar(20);
SET x := 100;
SET name := '张三';
SELECT x,name;
END //
DELIMITER ;
CALL p1();

注意要点:
DECLARE必须写在BEGIN...END块的前面- 必须指定类型(强类型),
用户自定义变量为弱类型- 作用域:只在BEGIN ...END内部
2. SQL编程
2.1 IF语句
结构化查询语言(StructuredQueryLanguage)简称为SQL,是一种特殊的编程语言,其中SQL也包含条件判断 ,循环 等等功能;
IF语句:
核心语法:
sql
IF 条件1 THEN
-- 语句
ELSEIF 条件2 THEN
-- 语句
ELSE
-- 语句
END IF;
示例:根据小萌的期末成绩来判断成绩等级:
sql
DELIMITER //
CREATE PROCEDURE p2(IN score INT)
BEGIN
IF score >= 90 THEN
SELECT '优秀';
ELSEIF score >= 60 THEN
SELECT '及格';
ELSE
SELECT '不及格';
END IF ;
END //
DELIMITER ;
CALL p2(99);
注意点:
- 与C和JAVA想必'
LSEIIF是一个单词而不是ELSE IF- 结束条件为
END IF(中间带有空格),如果没有结束条件,程序则不知道何时结束
存储过程里的IF 语句vs 普通查询里的IF(条件, 值1, 值2)函数

2.2 CASE语句
多分支选择,比多层 IF 更清晰。有两种写法,且既能当语句用(存储过程里),也能当表达式用(SELECT 里) 。
第一种简单的写法:简单的值匹配

例如:小萌在点外卖,买一号商品为:果汁,2号商品为猪脚饭,3号商品为桂林米粉
sql
DELIMITER //
CREATE PROCEDURE p3(IN id INT,OUT food varchar(20))
BEGIN
CASE id
WHEN 1 THEN
SET food := '果汁';
WHEN 2 THEN
SET food := '猪脚饭';
WHEN 3 THEN
SET food := '桂林米粉';
END CASE;
END //
DELIMITER ;
CAll p3(1,@food);
SELECT @food;
第二种写法:搜索CASE

还是以成绩为例子:
sql
DELIMITER //
CREATE PROCEDURE p4(IN score INT,OUT lever VARCHAR(20))
BEGIN
CASE
WHEN score>=90 AND score <=100 THEN
SET lever := '优秀';
WHEN score >=60 AND score <90 THEN
SET lever := '及格';
ELSE
SET lever :='非法参数';
END CASE;
END //
DELIMITER ;
CALL p4(99,@lever);
SELECT @lever;
注意事项:
- 当表达式 用结尾是
END;当语句 用(存储过程里)结尾是END CASEWHEN按顺序匹配,命中第一个就停止,所以条件顺序很重要ELSE可以省略,省略后如果都不匹配返回NULL
经典面试题:行转列
我们首先准备一张表插入并插入数据:
sql
-- 创建成绩表
CREATE TABLE score (
id INT PRIMARY KEY AUTO_INCREMENT,
student_name VARCHAR(20),
subject VARCHAR(20),
score INT
);
INSERT INTO score(student_name,subject,score) VALUES
('张三','语文',88),
('张三','数学',95),
('张三','英语',78),
('李四','语文',76),
('李四','数学',82),
('李四','英语',90);
目标效果:
| student_name | 语文 | 数学 | 英语 |
|---|---|---|---|
| 张三 | 88 | 95 | 78 |
| 李四 | 76 | 82 | 90 |
代码实现:
sql
SELECT
student_name,
SUM(CASE WHEN subject = '语文' THEN score ELSE 0 END) AS `语文`,
SUM(CASE WHEN subject = '数学' THEN score ELSE 0 END) AS `数学`,
SUM(CASE WHEN subject = '英语' THEN score ELSE 0 END) AS `英语`
FROM score
GROUP BY student_name;
逻辑梳理:
我们需要查询的是每一个人的成绩
第一步:先执行 CASE WHEN,还没分组、没求和
MySQL 先一行一行扫描整张表,对每一行 都执行 3 个 CASE 判断。
此时到这里就拿到了张三的每一条分散的记录
第二步:GROUP BY student_name
GROUP BY student_name告诉数据库:把名字相同的所有行,归为一组 。⚠️ 坑点来了:分组之后,一组里面有多条数据,不能直接返回多条,必须压缩成 1 行
所以必须使用聚合函数
SUM() / MAX()第三步:SUM () 聚合收拢,多行合并成一行

