存储的例程是一组可以存储在服务器中的SQL语句。完成此操作后,客户无需继续重新发出各个语句,而是可以引用存储的例程。
首先先进行存储的例程语法学习:
使用create procedure和create function语句创建存储的例程。
使用call语句调用过程,并且只能使用输出变量传回值。
可以像其他任何函数一样从语句内部调用一个函数(即,通过调用函数名称),并且可以返回标量值。
存储例程的主体可以使用复合语句
可以使用drop procedure和drop function语句删除存储的例程
可以使用alter procedure和alter function语句对其进行更改
简单演示:
- -- 声明结束符,因为mysql默认使用“;”作为结束符,而在存储过程中,会使用“;”作为一段语句的结束,导致“;”使用冲突
- delimiter $$
- CREATE PROCEDURE hello_procedure()
- BEGIN
- SELECT 'hello procedure';
- END $$
-
- CALL hello_procedure()
对于存储过程中的变量,可以类比java中的局部变量和成员变量的声明和使用;
用户自定义,在begin/end块中有效
语法:
声明变量: declare var_name type [default 'unkown'];
举例:declare nickname varchar(32);
set 赋值
- -- 声明结束符,因为mysql默认使用“;”作为结束符,而在存储过程中,会使用“;”作为一段语句的结束,导致“;”使用冲突
- delimiter $$
- create PROCEDURE sp_var01()
- BEGIN
- -- 局部变量(需要声明) 字符类型如果为char或者varchar,一定要表明单位长度,int可以不写
- DECLARE nickname VARCHAR(32) DEFAULT 'SF';
-
- select nickname;
-
- -- set赋值
- set nickname := 'UG';
-
- select nickname;
-
- END $$
-
- -- 使用call调用该函数
- call sp_var01()$$
-
- -- 使用drop删除该函数,若想要修改该存储函数,mysql只能drop之后重新create
- drop PROCEDURE sp_var01;
into 赋值
- -- 首先创建一张表
- DROP TABLE IF EXISTS `departments`;
- CREATE TABLE `departments` (
- `id` int(11) DEFAULT NULL,
- `dep_name` varchar(255) DEFAULT NULL
- ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-
- -- ----------------------------
- -- Records of departments
- -- ----------------------------
- INSERT INTO `departments` VALUES ('1', '开发');
- INSERT INTO `departments` VALUES ('2', '测试');
- INSERT INTO `departments` VALUES ('3', '产品');
- INSERT INTO `departments` VALUES ('4', '运维');
-
-
- -- 创建存储函数
- delimiter $$
- create PROCEDURE sp_var01_into()
- BEGIN
- -- 声明局部变量
- DECLARE dept_name VARCHAR(32) DEFAULT 'unkown';
- DECLARE dept_no int DEFAULT 0;
-
- -- select 查询要给局部变量赋值的属性 into 直接进行赋值
- SELECT d.id,d.dep_name into dept_no,dept_name from departments d where d.id = 1;
-
- select dept_no,dept_name;
- END $$
-
- call sp_var01_into()$$
-
- drop PROCEDURE sp_var01_into;
用户自定义,当前会话(连接)有效
语法:
@var_name
不需要提前声明,使用即声明
set 赋值
- delimiter $$
- create PROCEDURE sp_var02()
- BEGIN
- set @nick_name = 'WR';
- END $$
-
- CALL sp_var02 $$
- select @nick_name $$
into 赋值
- delimiter $$
- create PROCEDURE sp_var_into()
- BEGIN
- select d.dep_name into @deptname from departments d where d.id = 1;
- END $$
-
- CALL sp_var_into $$
- select @deptname $$
由系统提供,整个mysql服务器有效
语法:
@@global.var_name
由系统提供,整个Mysql服务器有效
语法:
@@global.var_name
-- 语法
in | out | inout param_name type
举例
- -- int 类型演示
- delimiter $$
- create PROCEDURE sp_param01(in age int)
- BEGIN
- set @user_age = age;
- end $$
- call sp_param01(10) $$
- SELECT @user_age $$
-
- delimiter $$
- create PROCEDURE sp_param03(in `name` VARCHAR(32))
- BEGIN
- set @user_name = `name`;
- end $$
- call sp_param03('liman') $$
- SELECT @user_name $$
-
-
-
-
- -- out 类型,只负责输出!
- -- 需求:输出传入的地址字符串对应的部门编号。
- delimiter $$
- create PROCEDURE sp_param02(in deptname VARCHAR(32),out dept_no int(11))
- BEGIN
- SELECT d.id into dept_no from departments d where d.dep_name = deptname;
- -- 此处强调,要么表起别名,要么入参名不与字段名一致
- end $$
-
- -- 测试
- delimiter ;
- set @dept_no = 7;
- call sp_param02("开发",@dept_no);
- select @dept_no;
-
-
- -- inout类型
- delimiter $$
- create PROCEDURE sp_param04(inout `name` VARCHAR(32))
- BEGIN
- set `name` = CONCAT('hello ',`name`);
- end $$
- delimiter ;
- set @user_name = '小明';
- call sp_param04(@user_name);
- SELECT @user_name;
if -- 语法
IF search_condition THEN statement_list
[ELSEIF search_condition THEN statement_list] ...
[ELSE statement_list]
END IF
举例:
- DROP TABLE IF EXISTS `emp`;
- CREATE TABLE `emp` (
- `empno` int(50) NOT NULL AUTO_INCREMENT,
- `ename` varchar(50) COLLATE utf8_general_mysql500_ci DEFAULT NULL,
- `job` varchar(50) COLLATE utf8_general_mysql500_ci DEFAULT NULL,
- `mgr` int(50) DEFAULT NULL,
- `hiredate` datetime DEFAULT NULL,
- `sal` decimal(10,2) DEFAULT NULL,
- `comm` varchar(25) COLLATE utf8_general_mysql500_ci DEFAULT NULL,
- `deptno` int(50) NOT NULL,
- PRIMARY KEY (`empno`)
- ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_general_mysql500_ci;
-
- -- ----------------------------
- -- Records of emp
- -- ----------------------------
- INSERT INTO `emp` VALUES ('1', 'smith', 'clerk', '7902', '1980-12-07 12:42:26', '8000.00', null, '1');
- INSERT INTO `emp` VALUES ('2', 'martmin', 'saleman', '1630', '1981-10-14 12:43:24', '10000.00', null, '2');
- -- 前置知识点:timestampdiff(unit,exp1,exp2)取差值,单位是unit
- select TIMESTAMPDIFF(YEAR,e.hiredate,now()) from emp e where e.empno = '2'
- delimiter //
-
- CREATE PROCEDURE sp_hire ()
- BEGIN
- DECLARE result VARCHAR (32) ;
- DECLARE years int;
- select TIMESTAMPDIFF(YEAR,e.hiredate,now()) into years from emp e where e.empno = '2';
-
- IF years > 40 THEN
- SET result = '元老' ;
- ELSEIF years > 38 THEN
- SET result = '老员工' ;
- ELSE
- SET result = '新手' ;
- END IF ;
- SELECT result ;
- END//
-
- delimiter ;
-
- CALL sp_hire();
case 语法:此语法是不仅可以用在存储过程,查询语句也可以用!
语法一(类比java的switch)
CASE case_value
when when_value then statement_list
[when when_value then statement_list] ...
[else statement_list]
END CASE语法二:
CASE
when search_condition then statement_list
[when search_condition then statement_list]
END CASE
举例:
- -- 需求:入职年限年龄<=38 是新手 >38<=40老员工 >40元老
- -- 语法一:
- -- 1.创建函数
- delimiter $$
- create PROCEDURE sp_hire_case_in(in year INT)
- BEGIN
- DECLARE result VARCHAR(32);
- DECLARE message VARCHAR(64);
- CASE year
- when 40
- then
- set result = '元老';
- set message = '老爷爷';
- when 38
- then
- set result = '老员工';
- set message = '油腻中年人';
- ELSE set result = '新手';
- set message = '萌新';
- end CASE;
- SELECT result,message;
- end $$
- delimiter;
-
- -- 2.调用函数
- call sp_hire_case_in(40);
-
- -- 3.删除函数
- drop PROCEDURE sp_hire_case_in;
-
- -- 语法二:
- -- 1.创建函数
- delimiter $$
- create PROCEDURE sp_hire_case()
- BEGIN
- DECLARE result VARCHAR(32);
- DECLARE message VARCHAR(64);
- CASE
- when TIMESTAMPDIFF(YEAR,'2001-01-01',now()) > 40
- then
- set result = '元老';
- set message = '老爷爷';
- when TIMESTAMPDIFF(YEAR,'2001-01-01',now()) > 38
- then
- set result = '老员工';
- set message = '油腻中年人';
- ELSE set result = '新手';
- set message = '萌新';
- end CASE;
- SELECT result,message;
- end $$
- delimiter;
-
- -- 2.调用函数
- call sp_hire_case();
-
- -- 3.删除函数
- drop PROCEDURE sp_hire_case;
-
-
-
LOOP 语法:
[begin_label:]LOOP
statement_list
END LOOP [end_label]举例:
需要说明,loop是死循环,需要手动退出循环,我们可以使用leave来退出
可以把leave看成我们Java中的break;
与之对应的,就有iterate(继续循环),类比java中的continue
死循环处理解决方法:
- -- 如有死循环处理,可以通过下面的命令查看并结束
-
- show processlist;
-
- kill id;
实例:
- -- 需求:循环打印到1到10
- -- leave控制循环的退出
- delimiter $$
- CREATE PROCEDURE sp_flow_loop()
- begin
- DECLARE c_index int DEFAULT 1;
- DECLARE result_str VARCHAR(256) default '1';
- cnt:LOOP
-
- if c_index >= 10
- then leave cnt;
- end if;
-
- set c_index = c_index + 1;
- set result_str = CONCAT(result_str,',',c_index);
-
- end loop cnt;
- select result_str;
-
- end $$
-
- delimiter ;
- call sp_flow_loop();
-
-
- delimiter $$
- create PROCEDURE sp_flow_loop02()
- begin
- DECLARE c_index int DEFAULT 1;
- DECLARE result_str VARCHAR(256) default '1';
- cnt:LOOP
-
- set c_index = c_index + 1;
- set result_str = CONCAT(result_str,',',c_index);
- if c_index < 10 then
- ITERATE cnt; -- 约等于java的continue
- end if;
- -- 下面这句话能否执行到?什么时候执行到
- leave cnt;
-
- end loop cnt;
- select result_str;
- END $$
-
- delimiter;
- call sp_flow_loop02();
REPEAT语法:相当于java中的 DO...WHILE...
[begin_label:]REPEAT
statement_list
until search_condition -- 直到... 为止 才退出循环
END REPEAT [end_label]
举例:
- -- 需求:循环打印1到10
- delimiter $$
- create PROCEDURE sp_flow_repeat()
- BEGIN
- DECLARE c_index int DEFAULT 1;
- -- 收集结果字符串
- declare result_str VARCHAR(256) DEFAULT '1';
- count_lab:REPEAT
- SET c_index = c_index + 1;
- set result_str = CONCAT(result_str,',',c_index);
- until c_index >= 10;
- end REPEAT count_lab;
- select result_str;
- end $$
- delimiter;
- call sp_flow_repeat();
while:类比Java中的while(){}
while语法:
[begin_label:] while search_condition DO
statement_list
END WHILE [end_label]
- -- 需求:循环打印1到10
- delimiter $$
- create PROCEDURE sp_flow_while()
- begin
- DECLARE c_index int DEFAULT 1;
- -- 收集结果字符串
- DECLARE result_str VARCHAR(256) DEFAULT '1';
-
- while c_index < 10 DO
- set c_index = c_index + 1;
- set result_str = CONCAT(result_str,',',c_index);
- end while;
- SELECT result_str;
- end $$
-
- delimiter ;
- call sp_flow_while();
leave:类比java的Break;
- -- 退出leave can be used within begin ... end or loop constructs(LOOP,REPEAT,WHILE).
- LEAVE label
ITERATE:类比java的continue;
- -- 继续循环 ITERATE can appear only within LOOP,and while statements
- ITERATE label
用游标得到某一个结果集,逐行处理数据 (不建议用,因为是一行一行进行扫描的,效率比较低)
类比 jdbc的resultSet
- -- 声明语法
- DECLARE cursor_name CURSOR FOR select_statement
-
- -- 打开语法
- OPEN cursor_name
-
- -- 取值语法(当fetch 到底 报错 no datas ) 每次只能一个值
- FETCH cursor_name into var_name [,var_name] ...
-
- -- 关闭语法
- CLOSE cursor_name
实例:
- -- 需求:按照部门名称查询员工,通过select查看员工的编号、姓名、薪资。(注意,此处仅仅演示游标用法)
- drop PROCEDURE if EXISTS sp_create_table;
-
- delimiter $$
- create PROCEDURE sp_create_table(in dept_name VARCHAR(32))
- BEGIN
- DECLARE emp_no int;
- DECLARE emp_name VARCHAR(32);
- DECLARE emp_sal DECIMAL(7,2);
-
- DECLARE lp_flag boolean DEFAULT true;
-
- DECLARE emp_cursor cursor FOR
- SELECT e.empno,e.ename,e.sal from emp e
- inner join departments d
- on e.deptno = d.id where d.dep_name = dept_name;
-
- -- handle 句柄
- DECLARE CONTINUE HANDLER for 1329 set lp_flag = false;
-
- OPEN emp_cursor;
-
- emp_loop:LOOP
- FETCH emp_cursor into emp_no,emp_name,emp_sal; -- 一个fetch每次只能取一个值
- if lp_flag then
- SELECT emp_no,emp_name,emp_sal;
- ELSE
- LEAVE emp_loop;
- END IF;
- END LOOP emp_loop;
- set @end_flag = 'end';
-
- CLOSE emp_cursor;
- END $$
- delimiter ;
- CALL sp_create_table('开发');
特别注意:
在语法中,变量声明、游标声明、handle声明是必须按照先后顺序书写的,否则创建存储过程出错。
- HANDLER 语法:
- DECLARE handler_action HANDLER
- for condition_value [,condition_value] ...
- statement
-
- handler_ation:{
- CONTINUE
- |EXIT
- |UNDO
- }
-
- conditon_value:{
- mysql_error_code
- |SQLSTATE [VALUE] sqlstate_value
- |conditon_name
- |SQLWARNING
- |NOT FOUND
- |SQLEXCEPTION
- }
信息加载中,请等待
微信客服(速回)
微信客服(慢回)