Mysql高级三 之 存储过程&函数

自闭症网瘾萝莉.ら 提交于 2020-01-29 20:33:11

Mysql高级三 之 存储过程和函数

1.存储过程和函数

1.1存储过程和函数概述

存储过程和函数是 事先经过编译并存储在数据库中的一段SQL语句的集合.调用存储过程和函数可以简化应用开发人员的很多工作,减少数据在数据库和应用服务之间的传输,对于提高数据处理的效率是有好处的.

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

函数:是一个返回值的过程

过程:是一个没有返回值的函数

1.2创建存储过程

CREATE PROCEDURE procedure_name([proc_parameeter[...]])
begin
	-- SQL语句
end

示例:

delimiter $

create procedure pro_test()
begin
	select 'Hello MySQL';
end$

delimiter;

结果:

在这里插入图片描述

delimiter:

该关键字用来声明SQL语句的分隔符,告诉MySQL解释器,该段命令是否已经结束了,Mysql是否可以执行了.
默认情况下,delimiter是分号;。在命令行客户端中,如果有一行命令以分号结束,那么回车后,MySQL将会执行该命令.

1.3调用存储过程

CALL pro_test;

结果:

在这里插入图片描述

1.4查看存储过程

-- 查看db_name数据库中的所有存储过程(这个存储在mysql 数据库下的 proc表中 如下tu)
select name form mysql.proc where db='db_name';

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

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

在这里插入图片描述

1.5删除存储过程

DROP PROCEDURE [IF EXISTS] sp_name;

示例:

drop procedure pro_test;

1.6 语法

存储过程是可以编程的,意味着可以使用变量,表达式,控制结构,来完成比较复杂的功能.

1.6.1 变量

  • DECLARE

    通过DECLARE可以定义一个局部变量,该变量的作用范围只能在BEGIN…END块中。

    DECLARE var_name[,...] type [DEFAULT value]
    

    示例:

    delimiter $
    
    create procedure pro_test2()
    begin 
    	declare num int default 5;
    	select num + 10;
    end$
    
    delimiter ;
    

    查询:

    CALL pro_test2;
    

    查看结果:
    在这里插入图片描述

  • SET

    直接赋值使用SET,可以赋常量值或者赋表达式,具体语法如下:

    SET var_name = expr[,var_name = expr] ...
    

    示例:

    delimiter $
    create procedure pro_list()
    begin
    	declare name varchar(20);
    	set name = 'MySQL';
        select name;
    end$
    
    delimiter;
    

    查看创建的存储过程

    CALL pro_list;
    

    结果:

在这里插入图片描述

也可以通过select … into 进行赋值

DELIMITER $

CREATE PROCEDURE pro_test3()
BEGIN
DECLARE num INT;
SELECT COUNT(*) INTO num FROM city;
SELECT CONCAT('city表中的记录数为:',num);
END$

DELIMITER ;

查看创建的存储过程

CALL  pro_test3();

结果:

在这里插入图片描述

1.6.2 if 条件判断

语法结构:

if search_condition then statement_list
	
	[elseif search_condition then statement_list] ...
	[else statement_list]
end if;

需求:

根据定义的身高变量,判定当前身高的所属身材类型
	180 及以上 -----------→ 身材高挑
	170 - 180 -----------→ 标准身材
	170 及以下 -----------→ 一般身材
DELIMITER $

CREATE PROCEDURE pro_test4()
BEGIN
	DECLARE height INT DEFAULT 175;
	DECLARE description VARCHAR(50) DEFAULT '';
	IF height >= 180 THEN
		SET description='身材高挑';
	ELSEIF height >= 170 AND height < 180 THEN
		SET description='标准身材';
	ELSE 
		SET description='一般身材';
	END IF;
	SELECT CONCAT('身高:',height,'对应身材类型:',description);
END$
DELIMITER ;

查询:

call pro_test4();

结果:

在这里插入图片描述

1.6.3 传递参数

create procedure procedure_name([in/out/inout] 参数名 参数类型)
...

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

IN-输入

需求:

根据定义的身高变量,判定当前身高的所属类型

示例:

DELIMITER $

create procedure pro_test5(in height int)
begin 
	declare description varchar(50) default '';
	if height >= 180 then
		set description='身材高挑';
	elseif height >= 170 and height < 180 then
		set description='标准身材';
	else
		set description='一般身材';
	end if;
		select concat('身高:',height,'对应身材类型:',description);
end$
DELIMITER ;

查询:

CALL pro_test5(171);

结果:

在这里插入图片描述

OUT-输出

需求:

根据传入的身高变量,获取当前身高的所属身材类型

示例:

DELIMITER $

CREATE PROCEDURE pro_test6(IN height INT, OUT description VARCHAR(100))
BEGIN
	IF height >= 180 THEN
		SET description='身材高挑';
	ELSEIF height >= 170 AND height < 180 THEN
		SET description='标准身材';
	ELSE
		SET description='一般身材';
	END IF;
END$

DELIMITER ;

查询:

CALL pro_test6(170,@description);
SELECT @description

结果:

在这里插入图片描述

科普:

@description : 这种变量要在变名称前面加上“@”符号,叫做用户会话变量,代表整个会话过程他都有作用的,这个类似于全局变量一样.(当前会话有效)

@@global.sort_buffer_size:这种在变量前加上“@@”符号叫做系统变量

1.6.4case结构

-- 方式一:
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] ...
    
    [ELSE statement_list]
    
END CASE;

示例:

给定一个月份,然后计算出所在的季度
DELIMITER $

CREATE PROCEDURE pro_test7(mouth INT)
BEGIN
   DECLARE result VARCHAR(10);
   CASE
   WHEN mouth>=1 AND mouth <= 3 THEN
    	SET result = '第一季度';
    WHEN mouth>=4 AND mouth <= 6 THEN
    	SET result = '第二季度';
    WHEN mouth>=7 AND mouth <= 9 THEN
    	SET result = '第三季度';
    ELSE
    	SET result = '第四季度';
    END CASE;
    SELECT CONCAT('传递的月份为:',mouth,';计算出的结果为:',result) AS content;
END$

DELIMITER ;

查询:

CALL pro_test7(1);

结果:

在这里插入图片描述

1.6.5 while循环

语法结构:

while search_condition do
	
	statement_list
	
end while;

需求:

计算从1加到n的值
CREATE PROCEDURE pro_test8(n INT)
BEGIN
	DECLARE total INT DEFAULT 0;
	DECLARE START INT DEFAULT 0;
	
	WHILE START <= n DO
		SET total = total + START;
		SET START = START + 1;
	END WHILE;
	SELECT total;
END$

DELIMITER ;

结果:

在这里插入图片描述

1.6.6repeat结构

有条件的循环控制语句,当满足条件的时候退出循环.while是满足条件才执行,repeat是满足条件退出循环.

语法结构:

REPEAT

	statement_list
	
	UNTIL search_condition
	
END REPEAT;

需求:

计算从1加到n的值

示例:

DELIMITER $

CREATE PROCEDURE pro_test9(IN n INT)
BEGIN
	DECLARE total INT DEFAULT 0;
	REPEAT
		SET total=total+n;
		SET n=n-1;
		UNTIL n=0
	END REPEAT;
	SELECT total;
END$

DELIMITER ;

查询:

CALL pro_test9(3);

结果:

在这里插入图片描述

1.6.7 loop语句

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

[begin_lable:] LOOP
	
	statement_list

END LOOP [end_label]

如果不存在statement_list中增加退出循环语句,那么LOOP语句可以用来实现简单的死循环.

1.6.8 leave语句

用来从标注的流程构造中退出,通常和BEGIN … END 或者循环一起使用.下面是一个使用LOOP和LEAVE的简单例子,退出循环:

DELIMITER $

create procedure pro_test11(n int)
begin
	declare total int default 0;
	
	ins: loop
		set total = total + n;
		set n = n - 1;
		if n <= 0 then
			leave ins;
		end if;
	end loop ins;
	select total;
end$

DELIMITER ;

查询:

CALL pro_test11(4);

结果:

在这里插入图片描述

1.6.9游标/光标

游标是用来存储查询结果集的数据类型,在存储过程和函数中可以使用光标对结果集进行循环的处理。光标的使用包括光标的声明、OPEN、FETCH和CLOSE,其语法如下.

声明光标:

DECLARE cursor_name CURSOR FOR select_statement;

OPEN光标:

OPEN cursor_name;

FETCH光标:

FETCH cursor_name INTO var_name[,var_name] ...

CLOSE光标:

CLOSE cursor_name;

示例:

初始化版本

CREATE TABLE emp(
	id INT(11) NOT NULL AUTO_INCREMENT,
	NAME VARCHAR(50) NOT NULL COMMENT '姓名',
	age INT(11) COMMENT '年龄',
	salary INT(11) COMMENT '薪水',
	PRIMARY KEY(id)	
)ENGINE=INNODB DEFAULT CHARSET=utf8;

添加信息:

insert into emp(id,name,age,salary) values
(null,'金毛狮王',55,3800),
(null,'白眉鹰王',60,4000),
(null,'青翼蝠王',38,2800),
(null,'紫衫龙王',42,1800);

-- 查询emp表中数据,并逐行获取进行展示 获取两条数据
DELIMITER $

CREATE PROCEDURE pro_test12()
BEGIN
	DECLARE e_id INT(11);
	DECLARE e_name VARCHAR(50);
	DECLARE e_age INT(11);
	DECLARE e_salary INT(11);
	DECLARE emp_result CURSOR FOR SELECT * FROM emp;
	OPEN emp_result;
	FETCH emp_result INTO e_id,e_name,e_age,e_salary;
	SELECT CONCAT('id=',e_id,', name=',e_name,', age=',e_age,', 薪资为:',e_salary);
	FETCH emp_result INTO e_id,e_name,e_age,e_salary;
	SELECT CONCAT('id=',e_id,', name=',e_name,', age=',e_age,', 薪资为:',e_salary);
	CLOSE emp_result;
END$

DELIMITER ;

查询:

call pro_test12();

结果:

在这里插入图片描述

在这里插入图片描述

-- 获取4条数据
DELIMITER $

CREATE PROCEDURE pro_test13()
BEGIN
	DECLARE e_id INT(11);
	DECLARE e_name VARCHAR(50);
	DECLARE e_age INT(11);
	DECLARE e_salary INT(11);
	DECLARE emp_result CURSOR FOR SELECT * FROM emp;
	OPEN emp_result;
	FETCH emp_result INTO e_id,e_name,e_age,e_salary;
	SELECT CONCAT('id=',e_id,', name=',e_name,', age=',e_age,', 薪资为:',e_salary);
	FETCH emp_result INTO e_id,e_name,e_age,e_salary;
	SELECT CONCAT('id=',e_id,', name=',e_name,', age=',e_age,', 薪资为:',e_salary);
	FETCH emp_result INTO e_id,e_name,e_age,e_salary;
	SELECT CONCAT('id=',e_id,', name=',e_name,', age=',e_age,', 薪资为:',e_salary);
	FETCH emp_result INTO e_id,e_name,e_age,e_salary;
	SELECT CONCAT('id=',e_id,', name=',e_name,', age=',e_age,', 薪资为:',e_salary);
	CLOSE emp_result;
END$

DELIMITER ;

通过循环结构获取游标的数据

DELIMITER $

CREATE PROCEDURE pro_test14()
BEGIN
	DECLARE e_id INT(11);
	DECLARE e_name VARCHAR(50);
	DECLARE e_age INT(11);
	DECLARE e_salary INT(11);
	DECLARE has_data INT DEFAULT 1;
	DECLARE emp_result CURSOR FOR SELECT * FROM emp;
	DECLARE EXIT HANDLER FOR NOT FOUND SET has_data=0;
	OPEN emp_result;
	
	REPEAT 
	FETCH emp_result INTO e_id,e_name,e_age,e_salary;
	SELECT CONCAT('id=',e_id,', name=',e_name,', age=',e_age,', 薪资为:',e_salary);
	UNTIL has_data = 0
	END REPEAT;
	CLOSE emp_result;
END$

DELIMITER ;

查询:


结果:(可以明显看见有1,2,3,4个结果)

在这里插入图片描述

1.7存储函数

语法结构:

CREATE FUNCTION function_name([param type ...])
RETURNS type
BEGIN
	...
END;

案例:

定义一个存储过程,请求满足条件的记录数;

DELIMITER $

CREATE FUNCTION count_city(countryId int)
returns int
begin
	declare cnum int;
	
	select count(*) into cnum from city where country_id = countryId;
	
	return cnum;
end$

DELIMITER ;

查询:

SELECT count_city(1);

结果:

在这里插入图片描述

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!