A brief introduction to MySQL 5.6 stored procedure and function syntax

MySQL supports stored routines (stored procedures and stored functions)

A stored routine is a set of SQL statements that can be stored in the server. After completing this operation, the customer does not need to continue to reissue individual statements, but can refer to stored routines.

First, learn the stored routine syntax:

Use create procedure and create function statements to create stored routines.

Use the call statement to call the procedure, and only use the output variable to return the value.

A function can be called from within a statement like any other function (that is, by calling the function name), and it can return a scalar value.

The body of the stored routine can use compound statements

You can use drop procedure and drop function statements to delete stored routines

It can be changed using alter procedure and alter function statements

Simple demonstration:

-- 声明结束符,因为mysql默认使用“;”作为结束符,而在存储过程中,会使用“;”作为一段语句的结束,导致“;”使用冲突
delimiter $$
CREATE PROCEDURE hello_procedure()
BEGIN 
  SELECT 'hello procedure';
END $$

CALL hello_procedure()

One, variables and assignment

For variables in the stored procedure, you can analogize the declaration and use of local variables and member variables in java;

1. Local variables:

User-defined, valid in the begin/end block

grammar:

Declare variables: declare var_name type [default'unkown'];

Example: declare nickname varchar(32);


set assignment

-- 声明结束符,因为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 assignment

-- 首先创建一张表
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;

2. User variables

User-defined, the current session (connection) is valid

grammar:

@var_name

No need to declare in advance, just use it

set assignment

delimiter $$
create PROCEDURE sp_var02()
BEGIN
	set @nick_name = 'WR';
END $$

CALL sp_var02 $$
select @nick_name $$

into assignment

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 $$

 

3. Session variables

Provided by the system, the entire mysql server is valid

grammar:

@@ global.var_name

4. Global variables

Provided by the system, the entire Mysql server is valid

grammar:

@@ global.var_name

Two, input and output

- Grammar

in | out | inout param_name type

For example

-- 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;

Three, process control-judgment

if -- 语法
IF search_condition THEN statement_list 
    [ELSEIF search_condition THEN statement_list] ...
    [ELSE statement_list]
END IF

For example: 

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 syntax: This syntax can be used not only in stored procedures, but also in query statements!

语法一(类比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

For example: 

-- 需求:入职年限年龄<=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;
 


Fourth, process control-loop

LOOP 语法:
[begin_label:]LOOP
        statement_list
END LOOP [end_label]

For example: It
    needs to be explained that loop is an infinite loop and needs to be manually exited. We can use leave to exit. We can
    regard leave as a break in our Java;
    correspondingly, there is iterate (continue loop), analogous to continue in java

Endless loop processing solution:

-- 如有死循环处理,可以通过下面的命令查看并结束

show processlist;

kill  id;

Examples: 

-- 需求:循环打印到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 syntax: equivalent to DO...WHILE... in java

[begin_label:]REPEAT
   statement_list
until search_condition - do not exit the loop until...
END REPEAT [end_label]

 

For example:

-- 需求:循环打印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: analogy to while () in Java {}

 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();

Five, process control-exit, continue the cycle

leave: Break in analogy to java;

-- 退出leave can be used within begin ... end or loop constructs(LOOP,REPEAT,WHILE).
LEAVE label

ITERATE: analogy to java's continue;

-- 继续循环 ITERATE can appear only within LOOP,and while statements
ITERATE label

Six, the cursor

Use the cursor to get a certain result set, and process the data row by row (not recommended, because it is scanned row by row, which is relatively inefficient)
analogous to jdbc's 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

Examples:

-- 需求:按照部门名称查询员工,通过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('开发');

pay attention:

In the syntax, variable declarations, cursor declarations, and handle declarations must be written in order, otherwise there will be an error in creating a stored procedure.

Seven, the handle in the stored procedure

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
}

 

Guess you like

Origin blog.csdn.net/LOVE_Me__/article/details/109158646