1. 视图(View)
视图是虚拟存在的表 ,只保存 SQL 逻辑,不保存查询结果。数据在使用时动态生成。
1.1 基本操作
-- 创建
CREATE [OR REPLACE] VIEW 视图名[(列列表)] AS SELECT语句 [WITH [CASCADED|LOCAL] CHECK OPTION];
-- 查询
SHOW CREATE VIEW 视图名;
SELECT * FROM 视图名;
-- 修改
ALTER VIEW 视图名[(列列表)] AS SELECT语句;
-- 删除
DROP VIEW [IF EXISTS] 视图名;
1.2 检查选项(CHECK OPTION)
对视图的 INSERT/UPDATE 操作进行约束检查。
|------------------|-------------------------------|
| 选项 | 说明 |
| CASCADED(默认) | 级联检查当前视图和所有依赖视图的条件 |
| LOCAL | 仅检查自身有 CHECK OPTION 的依赖视图 |
-- 示例:保护视图数据边界
CREATE VIEW v1 AS SELECT id, name FROM student WHERE id <= 20;
-- INSERT INTO v1 VALUES(25, 'Tom'); -- 允许插入(无 CHECK OPTION)
CREATE VIEW v2 AS SELECT id, name FROM v1 WHERE id >= 10 WITH CASCADED CHECK OPTION;
-- INSERT INTO v2 VALUES(25, 'Tom'); -- 拒绝(违反 id <= 20)
1.3 视图不可更新的情况
视图中包含以下任一内容,则不可更新(无法 INSERT/UPDATE/DELETE):
- 聚合函数(SUM、COUNT、AVG、MIN、MAX)
- DISTINCT
- GROUP BY / HAVING
- UNION / UNION ALL
- 子查询位于 SELECT 列表中
- 常量视图
1.4 视图的作用
|-----------|-----------------------|
| 作用 | 说明 |
| 简化操作 | 将复杂查询封装为视图,多次复用 |
| 安全性 | 限制用户只能访问特定行/列(屏蔽敏感字段) |
| 数据独立性 | 屏蔽底层表结构变化,上层应用无感知 |
2. 存储过程(Stored Procedure)
存储过程是预编译 并存储在数据库中的 SQL 集合,支持封装、复用、参数传递。
2.1 基本语法
-- 创建(命令行需先 DELIMITER $$ 改变分隔符)
CREATE PROCEDURE 名称([IN|OUT|INOUT 参数名 类型])
BEGIN
-- SQL 语句;
END;
-- 调用
CALL 名称([参数]);
-- 查看
SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA='库名';
SHOW CREATE PROCEDURE 名称;
-- 删除
DROP PROCEDURE [IF EXISTS] 名称;
2.2 参数模式
|------------|--------|
| 模式 | 说明 |
| IN(默认) | 传入参数 |
| OUT | 返回值 |
| INOUT | 既传入又返回 |
2.3 变量
-- 系统变量
SELECT @@session.autocommit;
SET SESSION autocommit = 0;
-- 用户定义变量
SET @name = 'Tom';
SELECT @name;
-- 局部变量(存储过程中)
DECLARE 变量名 类型 [DEFAULT 默认值];
2.4 流程控制
-- IF
IF 条件 THEN
...
ELSEIF 条件 THEN
...
ELSE
...
END IF;
-- CASE
CASE 变量
WHEN 值1 THEN ...
WHEN 值2 THEN ...
ELSE ...
END CASE;
-- WHILE
WHILE 条件 DO
...
END WHILE;
-- REPEAT
REPEAT
...
UNTIL 条件 END REPEAT;
-- LOOP(需配合 LEAVE 退出)
label: LOOP
...
IF 条件 THEN LEAVE label; END IF;
END LOOP label;
2.5 游标(Cursor)
用于逐行处理查询结果集。
-- 声明
DECLARE 游标名 CURSOR FOR 查询语句;
-- 打开
OPEN 游标名;
-- 获取一行
FETCH 游标名 INTO 变量1, 变量2, ...;
-- 关闭
CLOSE 游标名;
2.6 条件处理程序(Handler)
DECLARE {CONTINUE|EXIT} HANDLER FOR
{SQLSTATE 'code' | SQLWARNING | NOT FOUND | SQLEXCEPTION}
处理语句;
|----------|-------|
| 处理方式 | 说明 |
| CONTINUE | 继续执行 |
| EXIT | 退出当前块 |
2.7 完整示例
-- 根据年龄参数,查询用户姓名和专业,插入新表
CREATE PROCEDURE p1(IN uage INT)
BEGIN
DECLARE uname VARCHAR(100);
DECLARE upro VARCHAR(100);
-- 声明游标
DECLARE u_cursor CURSOR FOR SELECT name, profession FROM tb_user WHERE age <= uage;
-- 声明异常处理:游标读取完毕时关闭
DECLARE EXIT HANDLER FOR SQLSTATE '02000' CLOSE u_cursor;
-- 建表
DROP TABLE IF EXISTS tb_user_pro;
CREATE TABLE IF NOT EXISTS tb_user_pro(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100),
profession VARCHAR(100)
);
-- 打开游标循环
OPEN u_cursor;
WHILE TRUE DO
FETCH u_cursor INTO uname, upro;
INSERT INTO tb_user_pro VALUES(NULL, uname, upro);
END WHILE;
CLOSE u_cursor;
END;
CALL p1(30);
注意:先声明变量,再声明游标。游标声明必须在 Handler 声明之前。
3. 存储函数(Stored Function)
与存储过程类似,但必须有返回值。
CREATE FUNCTION 函数名([参数 类型, ...])
RETURNS 返回类型 [DETERMINISTIC]
BEGIN
-- SQL 逻辑
RETURN 值;
END;
-- 调用
SELECT 函数名(参数);
4. 触发器(Trigger)
在 INSERT / UPDATE / DELETE 前后自动触发执行。用于数据校验、日志记录、审计等场景。
目前 MySQL 只支持行级触发(FOR EACH ROW)。
4.1 NEW 和 OLD
|--------|-------|-------|
| 触发器类型 | NEW | OLD |
| INSERT | 新数据 | 无 |
| UPDATE | 修改后数据 | 修改前数据 |
| DELETE | 无 | 被删除数据 |
4.2 语法
CREATE TRIGGER 触发器名
{BEFORE | AFTER} {INSERT | UPDATE | DELETE}
ON 表名 FOR EACH ROW
BEGIN
-- SQL 语句(可通过 NEW.字段 / OLD.字段 引用数据)
END;
SHOW TRIGGERS; -- 查看
DROP TRIGGER [schema.]触发器名; -- 删除
4.3 示例:审计日志
CREATE TRIGGER user_log AFTER INSERT ON user FOR EACH ROW
BEGIN
INSERT INTO audit_log(user_id, action, create_time)
VALUES(NEW.id, 'INSERT', NOW());
END;
|------|-----------|------------|--------|-------------|
| 特性 | 视图 | 存储过程 | 函数 | 触发器 |
| 主要用途 | 封装查询,简化访问 | 封装业务逻辑 | 计算并返回值 | 自动响应 DML 事件 |
| 返回值 | 虚拟表 | 可选(OUT 参数) | 必须有 | 无 |
| 调用方式 | SELECT | CALL | SELECT | 自动触发 |