MySql数据库存储过程和函数

存储过程 和 函数

存储过程和函数是 事先经过编译并存储在数据库中的一段 SQL 语句的集合,调用存储过程和函数可以简化数数据库设计与开发的工作,减少数据在数据库和应用服务器之间的传输,因为应用服务器访问数据库的次数越多,数据传输效率越低,有了存储过程,应用服务器只需要访问一次数据库,就可以执行存储过程中封装的所有sql语句,对于提高数据处理的效率是有好处的。

存储过程函数的区别在于函数必须有返回值而存储过程没有

2 创建存储过程

语法:

CREATE PROCEDURE 存储过程名([存储过程需要的参数列表])
begin
-- 多条SQL语句
end;

案例:

-- 创建一个存储过程
-- 因为在命令行模式下end后要跟;表示存储过程结束,它前面的sql语句也要跟;表示该条语句结束,那么存储过程怎么写呢?
-- 我们可以用一条语句该别结束标记
DELIMITER $ -- 将结束标记修改为$
CREATE PROCEDURE pro_test()
BEGIN
SELECT 'Hello MySQL';
END$

3 调用存储过程

语法:

​ call 存储过程名()

     CALL pro_test();

4 查看存储过程

语法:

-- 查询指定数据库中的所有的存储过程
select name from mysql.proc where db='数据库名';

-- 查询存储过程的状态信息
show procedure status;

-- 查询某个存储过程的定义
show create procedure 存储过程名;

案例:

-- 查询指定数据库中的所有的存储过程
SELECT NAME FROM mysql.`proc` WHERE db='demo_01';

-- 查询存储过程的状态信息
SHOW PROCEDURE STATUS;

-- 查询某个存储过程的定义
SHOW CREATE PROCEDURE pro_test;

5 删除存储过程

语法:

drop procedure  存储结构名
     -- 删除存储过程
         DROP PROCEDURE pro_test;

6 变量

  • DECLARE

    通过 DECLARE 关键字可以定义一个变量,该变量的作用范围只能在BEGIN - END 块中

  • 语法

  • DECLARE 变量名[变量名2,变量名2...] 数据类型 [DEFAULT 默认值]

DELIMITER $
CREATE PROCEDURE pro_test2()
BEGIN
	DECLARE num INT DEFAULT 10;-- 声明变量
	SELECT CONCAT('num的值为:',num);-- concat()函数,将字符串进行拼接
END$
-- 执行存储过程
CALL pro_test2();

SET

直接赋值使用 SET,可以赋常量或者赋表达式。

语法:
SET 变量名 = 值或表达式
案例:

-- 变量赋值
DELIMITER $
CREATE PROCEDURE pro_test3()
BEGIN
	DECLARE num INT DEFAULT 0;
	SET num = num + 10;
	SELECT CONCAT('num的值为:',num);
END$

CALL pro_test3();

也可以通过select … into 进行变量赋值
案例:

-- select...into 赋值
DELIMITER $
CREATE PROCEDURE pro_test4()
BEGIN
	DECLARE num INT;
	SELECT COUNT(*) INTO num FROM city;
	SELECT CONCAT('共有',num,'个城市');
END$
-- 调用之后,我们给city表添加一条数据,再次执行存储过程,其值会相应的改变
CALL pro_test4();

7 if条件判断

语法结构

if 
	判断条件 
then 
	-- 如果成立则执行此处的sql语句
	sql语句
[elseif 判断条件 then sql语句] ...
[else sql语句]
end if;

案例:

-- if 选择结构
/*
 需求:根据成绩判断其所属的阶段:优秀,一般,良好
	socre>=90 优秀
	90>socre>=80 一般
	socre<80 良好
*/
DELIMITER $
CREATE PROCEDURE pro_test5()
BEGIN
  DECLARE score INT DEFAULT 95; -- 成绩变量
  DECLARE description VARCHAR(10) DEFAULT ''; -- 所属分段的描述信息
  IF 
      score>=90
    THEN
      SET 
         description='优秀';
    ELSEIF 
         score>=80 AND score<90
    THEN
      SET 
         description='一般';
    ELSEIF 
         score<80
    THEN
      SET
	description='良好';
  END IF;	
SELECT CONCAT('该同学的成绩为:',score,',属于',description);	
END$

CALL pro_test5();

8 传递参数

语法格式:

create procedure 存储过程名([in/out/inout] 参数名	参数类型)
	...

IN :   该参数可以作为输入,也就是需要调用方传入值 , 默认
OUT:   该参数作为输出,也就是该参数可以作为返回值
INOUT: 既可以作为输入参数,也可以作为输出参数


IN - 输入参数

案例:

-- 传递参数
-- in-输入参数
DELIMITER $
CREATE PROCEDURE pro_test6(IN score INT)
BEGIN
  DECLARE description VARCHAR(10) DEFAULT ''; -- 所属分段的描述信息
  IF 
      score>=90
    THEN
      SET 
         description='优秀';
    ELSEIF 
         score>=80 AND score<90
    THEN
      SET 
         description='一般';
    ELSEIF 
         score<80
    THEN
      SET
	description='良好';
  END IF;	
SELECT CONCAT('该同学的成绩为:',score,',属于',description);	
END$

CALL pro_test6(70);

OUT - 输出参数:

/*
需求:根据出入的成绩变量,获取当前成绩所属的分段(返回值)
*/
-- out-输入参数
DELIMITER $
CREATE PROCEDURE pro_test7(IN score INT,OUT description VARCHAR(10))
BEGIN
  IF 
      score>=90
    THEN
      SET 
         description='优秀';
    ELSEIF 
         score>=80 AND score<90
    THEN
      SET 
         description='一般';
    ELSEIF 
         score<80
    THEN
      SET
	description='良好';
  END IF;	
-- SELECT CONCAT('该同学的成绩为:',score,',属于',description);	
END$

CALL pro_test7(90,@description); -- @description 用户会话变量
SELECT @description;

注意:

​ **@变量名:**这种变量叫做用户会话变量,代表这个会话过程中,它都是有效的,一旦断开连接,或会话窗口关闭,则@变量会被全部释放。

@@变量名:系统变量

9 case结构

语法结构

方式一 :
CASE 所要判断的值
WHEN 是否匹配的值 THEN sql语句 -- 是否匹配的值 就相当于java中 case后面跟的值
[WHEN 是否匹配的值 THEN sql语句]
...
[ELSE sql语句] -- 相当于java中的default
END CASE;
	
方式二 :
CASE
WHEN 条件表达式 THEN sql语句 -- 条件表达式为真,则执行sql语句
[WHEN 条件表达式 THEN sql语句] ...
[ELSE sql语句]
END CASE;


案例:

/*
给定一个月份,计算该月所在的季度
*/
DELIMITER $
CREATE PROCEDURE pro_test8(IN mon INT)
BEGIN
DECLARE result VARCHAR(10);
  CASE
     WHEN mon>=1 AND mon<=3 THEN
        SET result='第一季度';
     WHEN mon>=4 AND mon<=6 THEN
        SET result='第二季度';
     WHEN mon>=7 AND mon<=9 THEN
        SET result='第三季度';
     WHEN mon>=10 AND mon<=12 THEN
        SET result='第四季度';
  END CASE;
  SELECT CONCAT(mon,'属于',result);
END$

CALL pro_test8(2);

10 while循环

当满足条件时,则执行循环

语法结构

while 条件 do
	sql语句
end while;
-- 条件成立,执行do后面的语句

案例:

/*
 计算从1 加到 n 的和
*/
DELIMITER $
CREATE PROCEDURE pro_test9(n INT) -- 默认是in 所以in可以省略
BEGIN
DECLARE total INT DEFAULT 0;
DECLARE num INT DEFAULT 1;
WHILE num<=n DO
 SET total = total+num;
 SET num=num+1;
END WHILE;
SELECT CONCAT('从1加到',n,'的和为',total);
END$

CALL pro_test9(100);

11 repeat循环

当满足条件时,则退出循环

语法结构

REPEAT
	sql语句
UNTIL 条件
END REPEAT;
-- 条件成立 结束循环

案例

-- repeat循环
/*
 计算从1 加到 n 的和
*/
DELIMITER $
CREATE PROCEDURE pro_test10(n INT) -- 默认是in 所以in可以省略
BEGIN
DECLARE total INT DEFAULT 0;
REPEAT
  SET total = total+n;
  SET n = n -1;
  UNTIL n=0 -- 这里没有;号 一定要注意
END REPEAT;
SELECT CONCAT('从1加到',n,'的和为',total);
END$

CALL pro_test10(100);

12 loop循环

LOOP 实现简单的循环,退出循环的条件需要使用其他的语句定义,通常可以使用 LEAVE 语句实现、
语法结构:

[别名:] LOOP
	sql语句
END LOOP [别名]
-- 如果不在 sql语句 中增加退出循环的语句,那么 LOOP 语句可以用来实现简单的死循环。

案例:

-- loop循环
/*
 计算从1 加到 n 的和
*/
DELIMITER $
CREATE PROCEDURE pro_test11(n INT) -- 默认是in 所以in可以省略
BEGIN
DECLARE total INT DEFAULT 0;
s:LOOP
	SET total = total+n;
	SET n=n-1;
  IF n<0 THEN
     LEAVE s;-- 退出循环
  END IF;
END LOOP s;
SELECT total;
END$

CALL pro_test11(99);

13 游标

概述:

游标是用来存储查询结果集的数据类型 , 在存储过程和函数中可以使用游标对结果集进行循环的处理。

​ 我们使用select语句查询出来的结果通过展示界面我们可以看到结果中的数据,但是我还想对查询出的数据进行进一步的处理,这样的话我们就需要一个容器来存储这个结果集,这个容器就是游标。

​ 游标的使用包括游戏】标的声明OPENFETCHCLOSE

//	 声明光标:
	     DECLARE 游标名 CURSOR FOR select语句 ; 
//	   OPEN 游标:
	     OPEN 游标名 ;
//	    FETCH 光标:
	     FETCH 游标名 INTO var_name [, var_name] ...-- 相当于java中的迭代器
		-- fetch 游标名 相当于 iterator.next()
//	CLOSE 光标:	
	CLOSE 游标名 ;
-- 准备一张测试表和几条数据
CREATE TABLE IF NOT EXISTS student(
id INT,#学号
NAME VARCHAR(20),#姓名
age INT,#年龄
sex VARCHAR(5),#性别
address VARCHAR(100),#地址
math INT,#数学
english INT#英语
);

INSERT INTO student (id,NAME,age,sex,address,math,english) VALUES 
(1,'马云',18,'男','杭州',80,80),
(2,'马化腾',19,'男','深圳',75,60),
(3,'埃隆马斯克',31,'男','美国',76,93),
(4,'扎克伯格',27,'男','美国',65,NULL),
(5,'郎平',16,'女','上海',90,98),
(6,'姚明',32,'男','上海',80,81);

-- 查询学生表中的数据,并进行逐行展示
DELIMITER $
CREATE PROCEDURE pro_test12()
BEGIN
   DECLARE id INT;#学号
   DECLARE NAME VARCHAR(20);#姓名
   DECLARE age INT;#年龄
   DECLARE sex VARCHAR(5);#性别
   DECLARE address VARCHAR(100);#地址
   DECLARE math INT;#数学
   DECLARE english INT;#英语
   DECLARE student_result CURSOR FOR SELECT * FROM student;-- 声明游标

   OPEN student_result;-- 开启游标
	FETCH student_result INTO id,NAME,age,sex,address,math,english; -- fetch一次,取一行记录
	SELECT CONCAT('id:',id,',name:',NAME,',age',age);
   CLOSE student_result;-- 关闭游标
END$

CALL pro_test12();

游标结合循环

思路1:

  1. 获取num = count(*)
  2. 每循环一次,num-1
  3. 当num=0时,退出
-- 循环改进
/*
 	1. 获取num = count(*)
 	2. 每循环一次,num-1
 	3. 当num=0时,退出
*/
DELIMITER $
CREATE PROCEDURE pro_test13()
BEGIN
   DECLARE id INT;#学号
   DECLARE NAME VARCHAR(20);#姓名
   DECLARE age INT;#年龄
   DECLARE sex VARCHAR(5);#性别
   DECLARE address VARCHAR(100);#地址
   DECLARE math INT;#数学
   DECLARE english INT;#英语
   DECLARE student_result CURSOR FOR SELECT * FROM student;-- 声明游标
   OPEN student_result;-- 开启游标
   SET @num = (SELECT COUNT(*)FROM student);
    REPEAT
	SET @num=@num-1;
	FETCH student_result INTO id,NAME,age,sex,address,math,english; -- fetch一次,取一行记录
	SELECT CONCAT('id:',id,',name:',NAME,',age',age);
    UNTIL @num=0
    END REPEAT;
   CLOSE student_result;-- 关闭游标
END$

CALL pro_test13();

思路2:句柄机制

  1. 先声明一个状态变量,初始值为1
  2. 声明句柄机制,当抓取不到数据就将该变量值设置为0
  3. 判断该状态变量的值决定循环是否继续进行
-- 方式2:句柄机制
DELIMITER $
CREATE PROCEDURE pro_test14()
BEGIN
   DECLARE id INT;#学号
   DECLARE NAME VARCHAR(20);#姓名
   DECLARE age INT;#年龄
   DECLARE sex VARCHAR(5);#性别
   DECLARE address VARCHAR(100);#地址
   DECLARE math INT;#数学
   DECLARE english INT;#英语
   DECLARE has_data INT DEFAULT 1; -- 状态变量,1代表有数据
   DECLARE student_result CURSOR FOR SELECT * FROM student;-- 声明游标
   -- 设置一个句柄机制,当抓取不到数据时触发句柄机制,执行set后操作
   DECLARE EXIT HANDLER FOR NOT FOUND SET has_data=0;
   OPEN student_result;-- 开启游标
    REPEAT
	FETCH student_result INTO id,NAME,age,sex,address,math,english; -- fetch一次,取一行记录
	SELECT CONCAT('id:',id,',name:',NAME,',age',age);
    UNTIL has_data = 0
    END REPEAT;
   CLOSE student_result;-- 关闭游标
END$
CALL pro_test14();

14 存储函数

存储过程 与 函数非常相似,存储过程虽然没有返回值,但是我们可以指定out来返回结果,所以存储函数能做的事情,存储过程也可以做。

  • 语法结构
CREATE FUNCTION 函数名([参数名 数据类型 ... ])
RETURNS 返回值类型
BEGIN
...
END;

  • 案例
-- 存储函数
-- 定义一个函数,通过国家id查询city表中对应有多少个城市
DELIMITER $
CREATE FUNCTION fun1(countryID INT)
RETURNS INT
BEGIN
 DECLARE cnum INT;
 SELECT COUNT(*) INTO cnum FROM city WHERE country_id = countryID;
 RETURN cnum;
END$

SELECT fun1(1);

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安宁#

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值