经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 数据库/运维 » MySQL » 查看文章
MySQL存储过程了解一下
来源:cnblogs  作者:布禾  时间:2021/4/12 9:47:28  对本文有异议

简介

存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL 语句集,它存储在数据库中,一次编译后永久有效,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程是数据库中的一个重要对象。

存储过程的使用

创建存储过程

语法:

  1. CREATE PROCEDURE 存储过程名( IN|OUT|INOUT 参数名 数据类型 , ...)
  2. BEGIN
  3. ...
  4. END;

MySQL存储过程的参数类型:

  1. IN,表示存储过程的输入参数,该参数的值将会传递给存储过程,在存储过程中可以对该参数进行修改,但是在存储过程返回时,该参数值不会被返回,相当于在存储过程中对该参数的修改对调用者来说是不可见的。

  2. OUT,表示存储过程的输入参数,该参数的值会在存储过程中初始化为NULL,当存储过程返回时,该值也会被返回,调用者可以看到被修改后的值。

  3. INOUT,表示存储过程的输入输出参数,该参数由调用者初始化,在存储过程中的做的任何更改都会被返回,调用者可以看到修改后的值。

存储过程创建示例:

创建存储过程student_procedure,student_procedure有一个输入参数age和一个输出参数num,查询tb_student表学生年龄大于等于输入参数age的人数,并将人数设置到num。

  1. CREATE PROCEDURE student_procedure(IN age TINYINT, OUT num INT)
  2. BEGIN
  3. SELECT COUNT(*) INTO num FROM tb_student t WHERE t.age>=age;
  4. END;

MySQL命令行创建存储过程:

如果是在MySQL命令行创建存储过程,则需要临时的修改语句分隔符,因为MySQL默认语句分隔符是;,会使存储过程中的语句被直接解析而导致语法错误。

  1. -- 设置//为语句分隔符
  2. mysql> DELIMITER //
  3. mysql> CREATE PROCEDURE student_procedure(IN age TINYINT, OUT num INT)
  4. -> BEGIN
  5. -> SELECT COUNT(*) INTO num FROM tb_student t WHERE t.age>=age;
  6. -> END;
  7. -> //
  8. Query OK, 0 rows affected
  9. --恢复为原来的分隔符
  10. mysql> DELIMITER ;
调用存储过程

tb_student表数据:

  1. +----+------+-----+-------------+-----------+----------+
  2. | id | name | age | phone | address | class_id |
  3. +----+------+-----+-------------+-----------+----------+
  4. | 1 | 小明 | 18 | 188xxxx1234 | xxxxxxxxx | 1 |
  5. | 2 | 小米 | 28 | 188xxxx1234 | xxxxxxxxx | 2 |
  6. | 3 | 小看 | 28 | 188xxxx1234 | xxxxxxxxx | 3 |
  7. | 4 | 小阿 | 38 | 188xxxx1234 | xxxxxxxxx | 3 |
  8. | 5 | 小鬼 | 48 | 188xxxx1234 | xxxxxxxxx | 3 |
  9. +----+------+-----+-------------+-----------+----------+

调用存储过程,查询年龄大于38的学生人数:

  1. -- 调用存储过程
  2. mysql> CALL student_procedure(38, @num);
  3. Query OK, 1 row affected
  4. -- 查看返回结果
  5. mysql> select @num;
  6. +------+
  7. | @num |
  8. +------+
  9. | 2 |
  10. +------+
查看存储过程的定义

语法:

  1. SHOW CREATE PROCEDURE proc_name;

如查看student_procedure的定义:

  1. mysql> SHOW CREATE PROCEDURE student_procedure;
  2. +-------------------+----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+--------------------+
  3. | Procedure | sql_mode | Create Procedure | character_set_client | collation_connection | Database Collation |
  4. +-------------------+----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+--------------------+
  5. | student_procedure | STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION | CREATE DEFINER=`root`@`localhost` PROCEDURE `student_procedure`(IN age TINYINT, OUT num INT) BEGIN SELECT COUNT(*) INTO num FROM tb_student t WHERE t.age>=age;END | utf8 | utf8_general_ci | utf8_general_ci |
  6. +-------------------+----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+--------------------+
修改存储过程

语法:

  1. ALTER PROCEDURE proc_name [characteristic ...]
  2. characteristic: {
  3. COMMENT 'string'
  4. | LANGUAGE SQL
  5. | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
  6. | SQL SECURITY { DEFINER | INVOKER }
  7. }

ALTER PROCEDURE 语句用于修改存储过程的某些特征。如果要修改存储过程的内容,可以先删除原存储过程,再以相同的命名创建新的存储过程。

删除存储过程

语法:

  1. DROP PROCEDURE [ IF EXISTS ] proc_name

如删除student_procedure:

  1. mysql> DROP PROCEDURE student_procedure;
  2. Query OK, 0 rows affected
  3. mysql> CALL student_procedure(38, @num);
  4. 1305 - PROCEDURE student_procedure does not exist

流程控制语句

IF语句

语法:

  1. IF 判断条件 THEN 处理语句
  2. [ELSEIF 判断条件 THEN 处理语句]...
  3. [ELSE 处理语句]
  4. END IF

示例:

  1. CREATE PROCEDURE test1(IN sex TINYINT)
  2. BEGIN
  3. IF sex=1 THEN SET @sex='男';
  4. ELSEIF sex=0 THEN SET @sex='女';
  5. ELSE SET @sex='未知';
  6. END IF;
  7. END;
CASE语句

CASE语句有两种写法:

语法1:

  1. CASE
  2. WHEN 1 THEN 处理语句
  3. [WHEN 2 THEN 处理语句]...
  4. [ELSE 处理语句]
  5. END CASE

语法2:

  1. CASE
  2. WHEN 条件判断 THEN 处理语句
  3. [WHEN 条件判断 THEN 处理语句] ...
  4. [ELSE 处理语句]
  5. END CASE

示例:

  1. -- 写法1
  2. CREATE PROCEDURE test2(IN sex TINYINT)
  3. BEGIN
  4. CASE sex
  5. WHEN 1 THEN SET @sex='男';
  6. WHEN 0 THEN SET @sex='女';
  7. ELSE SET @sex='未知';
  8. END CASE;
  9. END;
  10. -- 写法2
  11. CREATE PROCEDURE test3(IN sex TINYINT)
  12. BEGIN
  13. CASE
  14. WHEN sex=1 THEN SET @sex='男';
  15. WHEN sex=0 THEN SET @sex='女';
  16. ELSE SET @sex='未知';
  17. END CASE;
  18. END;
LOOP语句

LOOP循环是一个死循环,一般情况需要配合LEAVE语句和ITERATE语句使用,LEAVE语句表示跳出该循环(类似Java中的break),ITERATE语句表示跳出本次循环(类似Java中的continue)。

语法:

  1. [别名:]LOOP
  2. 处理逻辑
  3. END LOOP [别名]

示例:

  1. CREATE PROCEDURE test4()
  2. BEGIN
  3. SET @num=0;
  4. add_num:LOOP
  5. SET @num=@num+1;
  6. IF @num=10 THEN LEAVE add_num;
  7. END IF;
  8. END LOOP add_num;
  9. END;
REPEAT语句

REPEAT语句是自带条件判断的循环语句,每次语句执行完毕后,会对条件进行判断,如果为true则退出循环,否则继续循环。(类似Java中的do while循环)

语法:

  1. [别名:] REPEAT
  2. 处理语句
  3. UNTIL 条件判断
  4. END REPEAT [别名]

示例:

  1. CREATE PROCEDURE test5()
  2. BEGIN
  3. SET @num=0;
  4. add_num:REPEAT
  5. SET @num=@num+1;
  6. UNTIL @num=10 END REPEAT add_num;
  7. END;
WHILE语句

WHILE语句也是自带条件判断的循环,和REPEAT语句的区别在于WHILE语句会先进行条件判断,当条件判断为true时才继续执行循环中的语句,为false则直接退出循环。(类似于Java中的while循环)

语法:

  1. [别名:] WHILE 条件判断 DO
  2. 处理逻辑
  3. END WHILE [别名]

示例:

  1. CREATE PROCEDURE test6()
  2. BEGIN
  3. SET @num=0;
  4. add_num:WHILE @num<10 DO
  5. SET @num=@num+1;
  6. END WHILE add_num;
  7. END;

游标

游标是用来逐行处理某个查询的结果集。

游标的声明必须出现在HANDLER声明之前声明,变量和条件声明之后声明

创建游标:
  1. DECLARE 游标名称 CURSOR FOR sql查询;
打开游标:
  1. OPEN 游标名称;
使用游标:
  1. FETCH 游标名称 INTO 变量1 [,变量2]...

将结果集中的数据保存到对应的变量当中去,游标第一次使用时默认读取结果集中的第一行,一般配合循环语句逐行处理整个结果集。

关闭游标:
  1. CLOSE 游标名称;

CLOSE释放游标使用的所有内部内存和资源,因此每个游标不再需要时都应该关闭。游标关闭后不能使用,如果需要使用则需要重新打开游标。

示例

查询tb_student表,将所有学生名称连接成一个字符串设置到变量@name_Str中。

  1. CREATE PROCEDURE test7()
  2. BEGIN
  3. -- 声明局部变量student_name,用于接收数据集中的数据
  4. DECLARE student_name VARCHAR(10);
  5. -- 声明局部变量done,用于判断是否退出循环,默认值为FALSE
  6. DECLARE done INT DEFAULT FALSE;
  7. -- 声明游标my_cursor
  8. DECLARE my_cursor CURSOR FOR SELECT `name` FROM tb_student;
  9. -- 声明continue handler句柄,当出现SQLSTATE '02000'时将done设置为TRUE
  10. DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = TRUE;
  11. -- 设置用户变量@name_Str为空字符串
  12. SET @name_Str='';
  13. -- 打开游标
  14. OPEN my_cursor;
  15. -- 开始LOOP循环
  16. concat_name:LOOP
  17. -- 将数据集中的一行数据存放到指定的变量中
  18. FETCH my_cursor INTO student_name;
  19. -- 判断是否退出循环
  20. IF done THEN LEAVE concat_name;
  21. END IF;
  22. -- 连接学生名称字符串
  23. SET @name_Str = CONCAT(@name_Str,student_name);
  24. END LOOP concat_name;
  25. -- 关闭游标
  26. CLOSE my_cursor;
  27. END;

结果:

  1. mysql> call test7();
  2. Query OK, 0 rows affected
  3. mysql> select @name_Str;
  4. +----------------------+
  5. | @name_Str |
  6. +----------------------+
  7. | 小明小米小看小阿小鬼 |
  8. +----------------------+
关于SQLSTATE '02000'

在使用游标时,可以通过FETCH将数据集中的数据保存到变量中进行处理,但是当整个数据集已经FETCH结束的时候,再去FETCH就会抛异常:

  1. 1329 - No data - zero rows fetched, selected, or processed

该异常对应的SQLSTATE为02000,所以需要指定句柄捕获这种异常情况来给标志赋值,后续就可以通过这个标志来判断数据集循环读取结束。

异常信息详见:Error Reference

原文链接:http://www.cnblogs.com/seve/p/14634319.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号