当前位置:   article > 正文

Mysql存储过程和存储函数_mysql 存储过程 switch

mysql 存储过程 switch

存储过程的好处

  • 增强SQL语言的功能和灵活性:存储过程可以用控制语句编写,有很强的灵活性,可以完成复杂的判断和较复杂的运算。
  • 标准组件式编程:存储过程被创建后,可以在程序中被多次调用,而不必重新编写该存储过程的SQL语句。而且数据库专业人员可以随时对存储过程进行修改,对应用程序源代码毫无影响。
  • 较快的执行速度:如果某一操作包含大量的Transaction-SQL代码或分别被多次执行,那么存储过程要比批处理的执行速度快很多。因为存储过程是预编译的。在首次运行一个存储过程时查询,优化器对其进行分析优化,并且给出最终被存储在系统表中的执行计划。而批处理的Transaction-SQL语句在每次运行时都要进行编译和优化,速度相对要慢一些。
  • 减少网络流量:针对同一个数据库对象的操作(如查询、修改),如果这一操作所涉及的Transaction-SQL语句被组织进存储过程,那么当在客户计算机上调用该存储过程时,网络中传送的只是该调用语句,从而大大减少网络流量并降低了网络负载。
  • 作为一种安全机制来充分利用:通过对执行某一存储过程的权限进行限制,能够实现对相应的数据的访问权限的限制,避免了非授权用户对数据的访问,保证了数据的安全。

存储函数

创建存储函数

  • Mysql中有许多已经存在的存储函数,比如CONCAT(..),LENGTH(str)。但是我们也可以自己定义存储函数。
  • 格式如下:
  1. delimiter // -- 指定分割符
  2. create function fun_name()
  3. returns type -- type是执行存储函数返回的类型
  4. begin
  5. -- 执行其他的语句
  6. return (); -- 返回的数据
  7. end
  8. //
  9. delimiter ; -- 指定创建结束

复制

  • returns type : 指定存储函数返回的类型,比如returns char(50),returns int
  • 存储函数有且只有一个返回值
  • return () : 存储函数的返回值,这里的返回值类型需要和returns type中的类型一致,如果不一致会强制转换
    • return (select name from user where id=1);
  • 下面我们创建一个存储函数,返回user表中的id=1name
  1. delimiter //
  2. create function selectUserById()
  3. returns varchar(50)
  4. begin
  5. return (select name from user where id=1);
  6. end
  7. //
  8. delimiter ;

复制

指定参数
  • 在存储函数创建的时候还可以指定参数,这个参数是用户调用的时候输入的。
  • 存储函数中的参数默认是IN参数,而存储过程中的参数可以是INOUTINOUT
  • 直接使用parameter 类型指定即可,如果有多个参数可以使用,分割
  • 在调用的时候直接使用select funName(parmeter1,....);即可
  1. delimiter //
  2. create function selectUserById(uid int)
  3. returns varchar(50)
  4. begin
  5. return (select name from user where id=uid);
  6. end
  7. //
  8. delimiter ;

复制

调用存储函数

  • 存储函数是依赖数据库的,因此我们需要在指定的数据库中调用,或者前面指定数据库的名称
    • select selectUserById(); : 直接在存储函数所在数据库中调用
    • select dbName.selectUserById(); : 直接使用数据库的名称调用

删除存储函数

  • drop function selectUserById; :直接在存储函数所在数据库中直接删除存储函数
  • drop function dbName.selectUserById; :使用数据库名称删除存储函数

查看存储函数状态

  • 格式:show function status [like pattern] : 查看存储函数的状态
    • show function status \G : 查看所有的存储函数状态,\G是一种特定格式的输出
    • show function status like 'select%'\G :查看select开头的存储函数状态,\G是一种特定格式的输入。

查看存储函数的定义

  • 格式:show create function dbName.funName
    • show create function test.selectUserById \G; :查询test数据库中的存储函数selectUserById的定义,\G是一种特定的输出格式

修改存储函数

变量的使用

  • 变量的作用范围是begin.....end程序中

定义变量

  • 格式:declare var_name,.... type [default value]
    • declare age int default 22 :定义一个局部变量age,类型为int,默认值为22
    • declare var1,var2,var3 int : 定义三个局部变量,类型为int
  • 全部变量的声明一定要在赋值的前面,否则报错

定义用户变量

  • 用户变量以@开头
  • set @pin=10

为变量赋值

  • 格式:set var1=value1,[var2=value2,....]
    • set age=33; : 设置age的值为33
    • set var1=22,var2=33: 同时设置多个值
  1. declare var1,var2,var3 int;
  2. set var1=22,var2=33;
  3. set var3=var1+var2;

复制

  • 使用select col_name[,...] into var_name[,....] table_expr : 使用select查询得到的结果赋值给变量
    • 这个select把选定的列的值直接赋值给对应位置的变量
    • table_expr: 可以是表的查询条件,其中包含from 表名
  1. declare uname varchar(10); -- 定义变量uname
  2. declare uage int; -- 定义变量uage
  3. select name,age into uname,uage from user where id=1; -- 将id=1的用户姓名和年龄赋值给变量

复制

实例

在存储函数中使用
  • 在存储函数中定义局部变量,并且获取输出
  1. delimiter //
  2. create function selectUserById(uid int)
  3. returns varchar(50)
  4. begin
  5. declare uname varchar(50);
  6. select name into uname from user where id=uid;
  7. return uname;
  8. end
  9. //
  10. delimiter ;

复制

在存储过程中使用
  1. delimiter //
  2. create procedure selectUserById(IN uid int)
  3. begin
  4. declare offest,count int; -- 定义偏移量
  5. set offest=0,count=2; -- 赋值
  6. if uid is not null -- 如果uid不为null,按照id查询
  7. then select * from user where id=uid; -- 按照id查询
  8. else select * from user limit offest,count; -- 否则uid为null,按照分页查询前面两个
  9. end if;
  10. end
  11. //
  12. delimiter ;

复制

  • call selectUserById(1); : 查询id=1的用户信息
  • call selectUserById(null); :查询所有的用户信息,显示前面两个

注释

  • MySQL存储过程可使用两种风格的注释:
    • 双杠:–,该风格一般用于单行注释
    • C风格: 一般用于多行注释

流程控制标签的使用

  • beginend之间使用

IF - THEN - ELSEIF - ELSE -ENDIF

  • 格式
  1. begin
  2. if expression -- 判断条件
  3. then .... ; -- 条件成立执行
  4. elseif .....; -- 其他条件
  5. else ..... ; -- 条件相反执行
  6. endif; -- 结束if
  7. end

复制

  • 可以不是成对出现,比如只有if,或者if-else
  • 如果没有else,那么可以省略,比如if - then - endif
  • 判断相等使用=
  • 实例
  1. delimiter //
  2. create procedure selectUserById(IN uid int)
  3. begin
  4. declare offest,count int; -- 定义偏移量
  5. set offest=0,count=2; -- 赋值
  6. if uid is not null -- 如果uid不为null,按照id查询
  7. then select * from user where id=uid; -- 按照id查询
  8. else select * from user limit offest,count; -- 否则uid为null,按照分页查询前面两个
  9. end if;
  10. end
  11. //
  12. delimiter ;

复制

CASE - WHEN - THEN - ELSE - END CASE

  • 这个和java中的switch-case-default相似
  • 格式:
  1. case expr
  2. when value1 then ....;
  3. when value2 then .....;
  4. when......;
  5. ....
  6. else .......;
  7. end case;

复制

  • 实例
    • 创建一个存储过程,使用case
  1. delimiter //
  2. create procedure deleteUserById(IN uid int)
  3. begin
  4. case uid -- uid做选择
  5. when 1 -- uid==1
  6. then delete from user where id=1;
  7. when 2 -- uid==2
  8. then delete from user where id=2;
  9. else
  10. delete from user; -- 删除全部
  11. end case;
  12. end;
  13. //
  14. delimiter ;

复制

LOOP - ENDLOOP

  • LOOP只是创建一个循环执行的过程,并不进行条件判断,这个和while不一样,不需要判断条件,如果不跳出,那么将会永远的执行的下去。但是我们可以使用leave跳出循环
  • 格式:
  1. [LOOP_LABEL]:LOOP
  2. statement;
  3. END LOOP [LOOP_LABEL];

复制

  • 实例
    • 执行这个语句可以插入9条数据,如果i>=10跳出循环
  1. delimiter //
  2. create procedure insertUserByName(IN uname varchar(50))
  3. begin
  4. declare i int default 0;
  5. add_loop:loop -- 开始循环
  6. set i=i+1; -- id++操作
  7. insert into user(name) values(uname); -- 插入语句
  8. if i>=10
  9. then leave add_loop; -- 使用leave跳出循环
  10. end if;
  11. end loop add_loop; -- 结束循环
  12. end
  13. //
  14. delimiter ;

复制

LEAVE

  • 和循环一起使用,用于退出循环控制,见上面的例子

ITERATE

  • 格式:iterate label
  • iterate只可以出现在LOOPREPEATWHIE语句内,表示再次循环的意思,label表示循环的标志
  • 实例
    • 如果p<10重复执行p++
  1. delimiter //
  2. create procedure doiterate()
  3. begin
  4. declare p int default 0; -- 定义局部变量
  5. my_loop:loop
  6. set p=p+1; -- p++
  7. if p<10
  8. then iterate my_loop; -- 继续执行前面的循环的语句,p++
  9. elseif p>20
  10. then leave my_loop;
  11. end if
  12. select "p在10到20之间" -- 输出语句
  13. end loop my_loop;
  14. end
  15. //
  16. delimiter ;

复制

REPEAT

  • 这个也是循环语句,相当于do-while
  • 格式:
  1. [repeat_loop]: repeat
  2. statement_list;
  3. until exper -- 没有分号
  4. end repeat;

复制

  • 实例
  1. delimiter //
  2. create procedure dorepeat()
  3. begin
  4. declare p int default 0; -- 定义局部变量
  5. my_loop:repeat
  6. set p=p+1;
  7. select p;
  8. until p>10 -- 当p>10的时候循环结束
  9. end repeat my_loop;
  10. end
  11. //
  12. delimiter ;

复制

WHILE

  • 这个和REPEAT不同,先进行判断,然后才执行语句
  • 格式:
  1. [while_label]:while expr do
  2. statement_list;
  3. end while [while_lable];

复制

  • 实例
  1. delimiter //
  2. create procedure dowhile()
  3. begin
  4. declare p int default 0; -- 定义局部变量
  5. my_loop:while p<10 do -- 满足条件才执行
  6. set p=p+1; -- p++
  7. end while my_loop; -- 结束循环
  8. end
  9. //
  10. delimiter ;

复制

存储过程

  • 存储过程没有返回值

创建存储过程

  • 格式:
  1. delimiter //
  2. create procedure p_name([IN,OUT,INOUT]parameter 类型.....)
  3. begin
  4. -- 执行功能
  5. end
  6. //
  7. delimiter ;

复制

参数

  • 存储过程根据需要可能会有输入、输出、输入输出参数,如果有多个参数用”,”分割开。MySQL存储过程的参数用在存储过程的定义,共有三种参数类型,IN,OUT,INOUT:
    • IN参数的值必须在调用存储过程时指定,在存储过程中修改该参数的值不能被返回,为默认值
    • OUT:该值可在存储过程内部被改变,并可返回
    • INOUT:调用时指定,并且可被改变和返回

过程体

  • 过程体的开始与结束使用BEGINEND进行标识。

实例

  • 定义一个根据id查询的查询用户信息的存储过程,这里的id是由用户输入的,因此可以使用IN参数
  1. delimiter //
  2. create procedure selectUserById(IN uid int)
  3. begin
  4. select * from user where id=uid;
  5. end
  6. //
  7. delimiter ;

复制

调用存储过程

  • 格式:call procedure_name(...)
    • call selectUserById(1); : 直接在当前的数据库中调用存储过程selectUserById
    • call db_name.selectUsrById(1) : 指定数据库的名字调用

查看存储过程的状态

  • 格式:show procedure status like pattern \G
    • show procedure status like "select%"\G : 查看select开头的存储过程状态
    • show procedure status \G : 查看所有的存储过程状态
  • 查询的结果如下:
  1. *************************** 1. row ***************************
  2. Db: test -- 数据库名称
  3. Name: selectUserById -- 存储过程的名字
  4. Type: PROCEDURE
  5. Definer: root@localhost
  6. Modified: 2018-06-25 22:25:44
  7. Created: 2018-06-25 22:25:44
  8. Security_type: DEFINER
  9. Comment:
  10. character_set_client: utf8
  11. collation_connection: utf8_general_ci
  12. Database Collation: utf8_general_ci
  13. 1 row in set (0.01 sec)

复制

查看存储过程的定义

  • 格式:show create procedure db.pro_name
    • show create procedure test.selectUserById\G : 查询数据库test中存储过程的定义
  • 返回的结果如下:
  1. *************************** 1. row ***************************
  2. Procedure: selectUserById
  3. sql_mode: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
  4. Create Procedure: CREATE DEFINER=`root`@`localhost` PROCEDURE `selectUserById`(IN uid int)
  5. begin
  6. select * from user where id=uid;
  7. end
  8. character_set_client: utf8
  9. collation_connection: utf8_general_ci
  10. Database Collation: utf8_general_ci

复制

删除存储过程

  • 格式drop procedure pro_name
    • drop procedure selectUserById : 删除当前数据库的selectUserById的存储过程
    • drop procedure test.selectUserById;: 删除test数据库的selectUserById的存储过程

游标cursor

  • 在面对大量的数据的时候,游标能够一行一行的读取数据

声明游标

  • 格式:declare cursor_name cursor for select_statement
    • cursor_name : 游标的变量名称
    • select_statement :表示select语句,用于返回一个结果集给游标
  • 比如: declare users cursor for select name,age from user;

打开游标

  • 格式:open cursor_name;
    • open users

使用游标获取一行数据

  • 格式:fetch cursor_name into var_name[,var_name,...]
    • cursor_name:表示游标的名称
    • var_name : 表示将select语句查询到的一行信息存入到该参数中,var_name必须在声明游标之前定义好
  • 比如: fetch user into uname,uage

关闭游标

  • 格式:close cursor_name

实例

  • 使用游标获取user表中的一行数据
  1. delimiter //
  2. create procedure selectOneUser()
  3. begin
  4. declare uname varchar(50); -- 定义uname存储
  5. declare uage int; -- 定义uage存储
  6. declare users cursor for select name,age from user; -- 声明游标
  7. open users; -- 打开游标
  8. fetch users into uname,uage; -- 获取一行数据到存储到uname和uage中
  9. select uname as name,uage as age; -- 输出一行的结果
  10. close users; -- 关闭游标
  11. end
  12. //
  13. delimiter ;
  14. call selectOneUser(); -- 调用存储过程,此时只是输出第一行的数据

复制

  • 使用循环获取所有的数据
    • 这里使用循环获取,首先需要使用select count(*)获取总数
  1. delimiter //
  2. create procedure selectUsers()
  3. begin
  4. declare uname varchar(50); -- 定义uname存储
  5. declare uage int; -- 定义uage存储
  6. declare total int default 0; -- 定义count,这个用来统计总数
  7. declare i int default 1; -- 用来循环
  8. declare users cursor for select name,age from user; -- 声明游标
  9. select count(*) from user into total; -- 查询总数
  10. open users; -- 打开游标
  11. -- 开始循环遍历
  12. my_loop:while i<=total do
  13. set i=i+1; -- i++
  14. fetch users into uname,uage; -- 获取一行数据到存储到uname和uage中
  15. select uname as name,uage as age; -- 输出一行的结果
  16. end while my_loop;
  17. close users; -- 关闭游标
  18. end
  19. //
  20. delimiter ;
  21. call selectUsers(); -- 调用存储过程,获取全部数据

复制

  • 使用HANDLER判断游标是否还有元素
    • continue HANDLER for not found
    • 当游标中没有值的时候就会指定返回的值
  1. delimiter //
  2. create procedure selectUsers()
  3. begin
  4. declare uname varchar(50); -- 定义uname存储
  5. declare uage int; -- 定义uage存储
  6. declare flag int default 1; -- 创建结束游标的标志,默认值为1
  7. declare users cursor for select name,age from user; -- 声明游标
  8. declare continue HANDLER for not found set flag=0; -- 指定游标结束时的返回值
  9. open users; -- 打开游标
  10. my_loop:loop
  11. if flag=0 -- 这里使用=,否则报错
  12. then leave my_loop; -- 跳出循环
  13. end if;
  14. fetch users into uname,uage; -- 获取一行数据到存储到uname和uage中
  15. select uname as name,uage as age; -- 输出一行的结果
  16. end loop my_loop;
  17. close users; -- 关闭游标
  18. end
  19. //
  20. delimiter ;

复制

存储过程和存储函数的区别

  1. 存储函数可以使用return返回一个返回值,但是存储过程不能有返回值,如果需要实现返回的功能,可以使用OUT参数实现返回
  2. 存储函数只能有输入参数,而且不能带in, 而存储过程可以有多个in,out,inout参数。
  3. 存储过程中的语句功能更强大,存储过程可以实现很复杂的业务逻辑,而函数有很多限制,如不能在函数中使用insert,update,delete,create等语句;存储函数只完成查询的工作,可接受输入参数并返回一个结果,也就是函数实现的功能针对性比较强。
  4. 存储过程可以调用存储函数。但函数不能调用存储过程。
  5. 存储过程一般是作为一个独立的部分来执行(call调用)。而函数可以作为查询语句的一个部分来调用。

总结

  1. 存储过程中可以使用call调用其他的存储过程,但是不能使用drop语句删除其他的存储过程
  2. 存储过程的参数不要和数据库表的字段相同,否则将出现无法预料的结果

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/783817
推荐阅读
相关标签
  

闽ICP备14008679号