存储过程和触发器

一.存储过程

存储过程是什么?

存储过程是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,用户通过制定存储过程的名字和参数来执行,并获取相对应的结果

通俗来讲,存储过程可以理解为用SQL语言实现的方法

存储过程的优缺点

存储过程的优点:

1.性能优化:存储过程在创建时编译并存储在数据库中,执行速度比单个SQL语句快

2.代码重用:存储过程可以重复调用,减少重复代码,提高代码的可维护性

3.安全性:可以限制用户直接访问数据库,减少重复代码,提高代码的可维护性

4.事务管理:可以在存储过程中实现复杂的事务逻辑

5.降低耦合:当表结构发生变化时,只需要修改相应的存储过程,应用程序的改动较小

存储过程的缺点:

1.可移植性差:存储过程不能跨数据库移植,更换数据库时需要重新编写

2.调试困难:只有少数数据库管理系统支持存储过程的调试,开发和维护困难

3.不适合高并发场景:在高并发场景下,存储过程可能会增加数据库的压力,难以维护

存储过程的语法

1.创建

复制代码
-- 修改SQL语句标识符为//
DELIMITER //
-- 创建存储过程
CREATE PROCEDURE 存储过程名(参数列表)
BEGIN
    -- SQL语句
END //

-- 修改SQL语句标识符为;
DELIMITER ;

BEGIN 和END类似其他编程语言中的花括号

存储过程名类似方法名

SQL语句可以有多条语句

注意修改标识符之后一定还要修改回来,如果不修改,在命令行中执行存储过程创建语句时,遇到分号则会认为语句结束,无法正常创建

2.调用存储过程

call是调用存储过程的关键词

复制代码
-- 调用存储过程
CALL 存储过程名(参数列表);

3.查看存储过程

复制代码
-- 查看指定数据库中创建的存储过程
SELECT *FROM information_schema.ROUTINES WHERE ROUTINE_SHEMA='数据库名';
-- 查看存储过程的定义
SHOW CREATE PROCEDURE 存储过程名;

4.删除存储过程

复制代码
DROP PROCEDURE [IF EXISTS] 存储过程名;

二.变量

SQL中变量有三类,分别为:系统变量,用户自定义变量以及局部变量,下面将分别介绍这三种变量

系统变量

系统变量是MySQL服务器的配置变量,控制着服务器的行为和性能.分为全局变量(GLOBAL)和会话变量(SESSION)

全局变量 启动的是读取的值

会话变量 可以针对每个对话进行自定义设置

1.查看系统变量

复制代码
-- 查看所有的系统变量
SHOW [GLOBAL|SESSION] VARIABLES;
-- 查看指定的系统变量
SHOW [GLOBAL|SESSION] VARIABLES LIKE 'XXX';
--查看指定的系统变量,可以通过LIKE进行模糊查询
SHOW [GLOBAL|SESSION] VARIABLES LIKE '%XXX%';
--使用SELECT查看指定的系统变量
SELECT @@[GLOBAL|SESSION].系统变量名;


--示例:查看以auto开头的全局系统变量
SHOW GLOBAL VARIABLES LIKE 'AUTO%';
--示例:查看以char开头的会话系统变量
SHOW SESSION VARIABLES LIKE 'char%';

注意:两个@@表示查询系统变量

2.设置系统变量

复制代码
SET [GLOBAL|SESSION] 系统变量名 =值;
SET @@SESSION.系统变量名 =值;

--示例:设置事务自动提交会话变量为关闭/开启
SET @@SESSION.autocommit=0;
SET autocommit=1;

如果没指定GLOBAL|SESSION ,默认设置会话(SESSION)全局变量

会话关闭后,设置的会话(SESSION)变量失效;新建的会话读取全局系统变量的值作为初始值

MySQL重启后,设置的全局(GLOBAL)变量失效,如果想要使全局系统变量永久生效,需要修改选项文件

修改会话级别的值,不影响全局变量的值

用户自定义变量

用户自定义变量是在SQL会话中定义的变量,不用提前声明,作用域为当前对话

作用是保存查询的中间结果,以便后面使用

1.赋值操作

复制代码
-- 方式一
SET @var_name=expr[,@var_name]...
-- 方式二(推荐使用)
SET @var_name :expr[,@var_name]...
-- 方式三: 在SELECT语句中
SET @var_name :expr[,@var_naem]...
-- 方式四:查询结果赋值给自定义变量
SELECT 列名 INTO @var_name FROM 表名  WHERE...;

2.使用用户自定义变量

复制代码
-- 示例: 定义一个age变量并赋值为18,并查看
SET @age := 18;
SELECT @age;
-- 示例:从学生表中查询编号为1的学生学号并赋值给sno变量
SELECT sno INTO @sno from student where id=1;
SELECT @sno;
-- 示例:查询学生表中的总记录数并赋值给count
SELECT count(*) INTO @count from student;
SELECT @count;

由于SQL中比较相等用的也是等号(=),所以赋值变量的时候推荐使用(:=)

局部变量

局部变量只在存储过程,函数或触发器的范围内有效.需要使用DECLARE声明,作用域的范围在声明的BEGIN...END块内

1.声明

复制代码
DECLARE 变量名  变量类型  [DEFAULT 默认值....];

2.赋值

复制代码
-- 方式一:
SET var_name =值;
-- 方式二(推荐使用):
SET var_name := 值;
--方式三: 查询结果并赋值给自定义变量
SELECT 列名 INTO var_name FROM 表名 WHERE ...;

3.局部变量的使用

复制代码
delimiter //
-- 创建存储过程
create PROCEDURE p1()
BEGIN
    -- 定义一个局部变量
    declare  stu_count INT DEFAULT 0;
    -- 查询结果赋值给局部变量
    select count(*) INTO stu_count from student;
    -- 使用局部变量
    select stu_count;
END //
delimiter ;
-- 调用存储过程
CALL p1();
select count(*) from student;

4.注意事项

1.变量名不分大小写

2.在存储过程和函数中,局部变量必须在使用前声明

3.用户自定义变量在会话结束时失效,而局部变量在存储过程或函数结束时失效

4.避免使用保留字作为变量名

三.SQL编程

结构化查询语言(Structured Query Language)简称SQL,是一种特殊目的的编程语言,是一种数据库查询和程序设计语言,用于存取数据以及查询,更新和管理关系数据库系统

条件判断IF语句

1.语法

复制代码
IF 条件1 THEN
    ......
    [ELSEIF 条件1 THEN
      ......
    ELSE
        ......]
END IF;

2.使用

复制代码
-- 创建存储过程
delimiter //
create procedure p2()
BEGIN 
DECLARE score INT DEFAULT 80;
DECLARE result VARCHAR(10);
   IF score >=90 THEN 
     SET result :="优秀";
   ELSEIF score>=80 AND score <90 THEN 
     SET result :="良好"; 
   ELSEIF score>=60 AND score <80 THEN 
     SET result :="及格";
   ELSE
     SET result :="不及格";
   END IF;
SELECT result;
END //
delimiter  ;
call p2();

参数

1.分类

|-------|---------------------------|
| 类型 | 描述 |
| IN | 输入类型,调用存储过程时要传入的值,默认参数类型 |
| OUT | 输出类型,可以作为存储过程的返回值 |
| INOUT | 输入输出类型,既可以作为输入类型也可以作为输出类型 |

2.使用

复制代码
DELIMITER //
CREATE PROCEDDURE 存储过程名([IN/OUT/INOUT  参数名 参数类型][,...])
BEGIN
  --SQL 语句
END //
DELIMITER ;

CASE

1.语法一

CASE 后的case_value 是一个表达式,该表达式的值与每一个WHEN子句中的when_value比较,当找到一个相等的when_value时,执行相应的statement

如果没有相等的when_valut,则执行ELSE子句中的 statement

复制代码
-- 语法一:
CASE case_value
    WHEN when_value THEN statement_list
     [WHEN when_value THEN statement_list]...
      [ELSE statement_list]
END CASE

2.语法二

计算每个WHEN子句search_condition表达式,直到其中一个表达式为真,此时执行相应的THEN子句中的statement_list

如果search_condition都不相等,则执行ELSE 子句中的statement_list(如果存在else)

不具有向下穿透的能力

复制代码
--语法二
CASE
    WHEN search_condition THEN statement_list
     [WHEN search_condition THEN statement_list]...
      [ELSE statement_list]
END CASE

注意:每个statement_list由一条或多条SQL语句组成且不允许为空,但可以使用BEGIN..END;块

如果没哟when_value或search_condition与测试值匹配,并且CASE语句不包含ELSE子句,则会导致CASE语句错误

循环

WHILE

语法

先判断条件表达式search_condition是否为TRUE,如果条件成立,则执行循环体中的statement_list

复制代码
WHILE search_condition DO 
      statement_list
END WHILE;

REPEAT

语法:(类似于do while)

先执行一次循环体中的statement_list,再判断条件表达式search_condition是否为TRUE,如果条件成立,则继续执行循环体中的语句,如果不成立则退出循环

复制代码
REPEAT 
    statement_list
   UNTIL search_condition
END REPEAT;

LOOP

LOOP也可以实现一个简单的循环,并且当满足某个条件时终止当前循环或者退出整个循环,通常配合以下两个子句使用(如果不加以下子句相当于while)

LEAVE label: 退出整个循环,类似JAVA中的break;

ITERATE label:终止当前循环,类似JAVA中的continue;

语法:

复制代码
[begin_label:] LOOP
     statement_list
END LOOP [end_label]

游标

MySQL中的游标是一种数据库对象,允许在存储过程和函数中对查询到的结果集进行逐行检索

语法:

1.使用游标之前必须先声明游标,之后使用OPEN ,FETCH和CLOSE语句来打开游标、获取游标记录和关闭游标

2.游标必须在处理程序之前被声明,并且变量必须在游标或处理程序之前被声明

复制代码
-- 声明游标
DECLARE 游标名 CURSOR FOR 查询语句;
-- 打开游标
OPEN 游标名
-- 获取游标记录
FETCH 游标名 INTO 变量[,变量]...;
-- 关闭游标
CLOSE 游标名;

条件处理程序

定义条件时事先定义程序执行过程中可能遇到的问题,处理程序定义了在遇到问题时应采用的处理方式

使用条件处理程序保证存储过程或函数在遇到警告或错误时能继续执行,可以增强程序处理问题的能力,避免程序异常停止运行

复制代码
DECLARE handler_action HANDLER
    FOR condition_value[,condition_value]...
    statement
handler_action:{
       CONTINUE  -- 继续执行当前程序
     | EXIST     -- 终止当前程序
}

condition_value:{
    mysql_error_code    --MYSQL错误码
   |SQLSTATE [VALUE] sqlstat_value  --状态码
   |SQLWARNING --所有以01开头的SQLSTATE代码
   |NOT FOUND  --所有以02开头的SQLSTATE代码
   |SQLEXCEPTION  --所有没有被SQLWARNING或NOT FOUND捕获的SQLSTATE代码
}

变量声明---游标声明--条件处理程序声明

存储函数

定义:

MySQL存储函数是有返回值的存储过程,参数只能是IN类型,类似于内置函数. 存储函数与存储过程的主要区别在于存储函数必须要有返回值,而存储过程则不一定

(一般情况下,我们还是使用存储过程,存储函数对参数的要求较高)

语法:

复制代码
CREATE FUNCTION 存储函数名称([参数列表])
RETURNS type[]characteristic...]
BEGIN
   --sql语句
   RETURN ...;
END;

characteristic :
    [NOT] DETERMINISTIC --表示相同的输入参数总是产生[不同]相同的结果
   |NO SQL -- 不包含SQL语句
   |READS SQL DATA --包含读取数据的语句,如select
   |MODIFIES SQL DATA --包含写入数据的语句,如update,delete

-- 使用存储过程
select 存储函数名称([参数类表]);

只能是输入类型的参数

在MySQL8.0版本中,如果binlog是开启的,那么在定义存储函数时,需要指定characteristic特性,否则会报错

四.触发器

1.什么是触发器

触发器是一个与表关联的数据库对象,在对表进行insert、update、delete操作时,触发并执行定义触发器时指定的SQL语句

触发器可以在对表操作之前或者之后执行,这被称为触发时间

触发器可以执行SQL语句或逻辑块,用于实施复杂的业务逻辑或数据验证

MySQL支持三种类型的触发器:INSERT触发器、UPDATE触发器、DELETE触发器。使用OLD和NEW关键词来引用触发器中发生变化的记录内容

|-----------|-------------------------------|
| 触发器类型 | OLD和NEW |
| INSERT触发器 | NEW表示将要或者已经新增的数据 |
| UPDATE触发器 | OLD表示修改之前的数据,NEW表示将要或者已经修改的数据 |
| DELETE触发器 | OLD表示将要或者已经删除的数据 |

行级触发器和语句级触发器

行级触发器:当对表中的每一行进行INSERT,UPDATE或DELETE操作时,行级触发器都会被处罚

语句级触发器:在整个INSERT,UPDATE,DELETE语句执行时只触发一次

MySQL只支持行级触发器,不支持语句级触发器

2.语法:

复制代码
-- 创建
CREATE TRIGGER [IF NOT EXISTS] trigger_name
    trigger_time trigger_event
    ON tbl_name FOR EACH ROW
BEGIN
    trigger_stmt;
END;

trigger_time:{BEFORE|AFTER}

trigger_event:{INSERT|UPDATE|DELETE}
 

--查看触发器
show TRIGGERS;

--删除,如果没有指定schema_name,默认当前数据库
DROP TRIGGER [IF EXISTS] [schema_name.]trigger_name;
相关推荐
q***12531 小时前
PostgreSQL_安装部署
数据库·postgresql
q***48251 小时前
mysql用户名怎么看
数据库·mysql
夏日玲子2 小时前
【Redis】Redis常用命令合集
数据库·redis·缓存
万邦科技Lafite2 小时前
1688图片搜索商品API接口(item_search_img)使用指南
java·前端·数据库·开放api·电商开放平台
自在极意功。2 小时前
SQL查询语句深度解析:从基础到进阶,写出高效优雅的SQL!
数据库·sql
north_eagle2 小时前
MySQL 业务数据,报表方案
大数据·数据库
r***12382 小时前
Spring boot启动原理及相关组件
数据库·spring boot·后端
数据库学啊2 小时前
大数据场景下时序数据库选型指南:TDengine为什么凭借领先的技术和实践脱颖而出?
大数据·数据库·时序数据库·tdengine
t***D2643 小时前
MySQL安全
数据库·mysql·安全