MySQL-存储过程&&函数

存储过程

  1. 存储过程概念
存储过程是一些sql语句和控制语句组成的被封装起来的过程,它驻留在数据库中,可以被客户应用程序通过存储过程名字调用,也可以从另一个存储过程或触发器调用。
它的参数可以被传递和返回,与应用程序中的函数过程类似,存储过程可以通过名字来调用,具有输入参数和输出参数。
存储过程分类
1) 返回记录集的存储过程 ----从数据库返回符合一个或几个条件的记录
2) 返回数值的存储过程(标量存储过程)----在数据库执行一个有返回值的函数或命令
3) 行为存储过程 -----在数据库中的更新和删除操作
为什么要是用存储过程?
(1)执行速度快——存储过程只在创建时进行编译,以后每次执行存储过程都不需要重新编译,而一般SQL语句没执行一次就需编译一次,所以使用存储过程可提高数据库的执行速度。
(2)减少网络通信量——当对数据库进行复杂操作时,(如对多个表进行insert、update、select、delete时)可将这些复杂操作用存储过程封装起来与数据库提供的事务处理结合一起使用。这些操作,如果用程序完成就是多条SQL语句,可能要多次连接数据库,而换成存储过程只需一次连接。
(3)更强的适应性与复用性——存储过程可以重复使用,提高了可重用性,减少数据库开发人员的工作量。
(4)可维护性高——更新存储过程通常比更改、测试以及重新部署程序集需要较少的时间和精力。
(5)安全性高,可设定只有某用户才能对指定存储过程的使用权,且存储过程比多条sql稳定,只要数据库不出现问题,基本上是不会出现什么问题的。
(6)分布式工作——应用程序和数据库的编码工作可以单独进行,减少耦合度。
(7)更好的版本控制,通过svn等源代码控制工具可以轻松恢复或引用旧版本的存储过程。
存储过程的缺点
(1)开发调试差:无良好的IDE开发工具,存储过程的调试比一般SQL要复杂的多。
(2)可移植性差:由于存储过程将应用程序绑定到数据库上,因此使用存储过程封装业务逻辑将限制应用程序的可移植性。
(3)重新编译问题,因为后端代码是运行前编译的,如果带有引用关系的对象发生改变时,受影响的存储过程、包将需要重新编译(不过也可以设置成运行时刻自动编译)。
(4)如果在一个程序系统中大量的使用存储过程,到程序交付使用的时候随着用户需求的增加会导致数据结构的变化,接着就是系统的相关问题了,最后如果用户想维护该系统可以说是很难很难、而且代价是空前的,维护起来更麻

基本语法:

delimiter
create procedure  procedure_name(IN|OUT|INOUT)
begin
      mysql操作语句;
end;
delimiter $$  #将语句的结束符号从分号;临时改为两个$$(可以是自定义)
CREATE PROCEDURE delete_matches(IN p_playerno INTEGER)
BEGIN
DELETE FROM MATCHES
WHERE playerno = p_playerno;
END$$
delimiter ;
call delete_matches()

注意:每个嵌套块及其中的每条语句,必须以分号结束

  • IN 输入参数:表示调用者向过程传入值(传入值可以是字面量或变量)
  • OUT 输出参数:表示过程向调用者传出值(可以返回多个值)(传出值只能是变量)
  • INOUT 输入输出参数:既表示调用者向过程传入值,又表示过程向调用者传出值(值只能是变量)

变量相关

1、变量

局部变量声明一定要放在存储过程体的开始

DECLARE variable_name [,variable_name...] datatype [DEFAULT value];

DECLARE l_int int unsigned default 4000000;   
DECLARE l_numeric number(8,2) DEFAULT 9.95;  
DECLARE l_date date DEFAULT '1999-12-31';  

2、变量赋值

SET 变量名 = 表达式值 [,variable_name = expression ...]

declare var1 int;
set var1 =1;

3、用户变量

SELECT 'Hello World' into @x;
SELECT @x;
SET @y='Goodbye Cruel World';  
SELECT @y;

在存储过程中使用用户变量

CREATE PROCEDURE GreetWorld( ) SELECT CONCAT(@greeting,' World'); 

4、包含if-else

DELIMITER //  
CREATE PROCEDURE proc1(IN parameter1 INTEGER)   
BEGIN   
    DECLARE variable1 CHAR(10);   
    IF parameter1 = 17 THEN   
        SET variable1 = 'birds';   
        SET variable1 = 'beasts';   
    END IF;   
    INSERT INTO table1 VALUES (variable1);  
 END  //  
 DELIMITER ;

5、存储过程的修改

ALTER PROCEDURE

6、case语句:

DELIMITER //  
CREATE PROCEDURE proc3 (in parameter int)  
begin 
    declare var int;  
    set var=parameter+1;  
    case var  
        when 0 then   
             insert into t values(17);  
        when 1 then   
             insert into t values(18);  
             insert into t values(19);  
    end case;  
end//  
DELIMITER ;

7、 循环语句

DELIMITER //  
CREATE PROCEDURE proc4()  
     -> begin 
     -> declare var int;  
     -> set var=0;  
     -> while var<6 do  
     -> insert into t values(var);  
     -> set var=var+1;  
     -> end while;  
     -> end;  
mysql > DELIMITER ;

8、repeat···· end repeat

repeat
--循环体
until 循环条件
end repeat;

mysql > DELIMITER //  
mysql > CREATE PROCEDURE proc5 ()  
     -> begin   
     -> declare v int;  
     -> set v=0;  
     -> repeat  
     -> insert into t values(v);  
     -> set v=v+1;  
     -> until v>=5  
     -> end repeat;  
     -> end;  
mysql > DELIMITER ;



完整的例子

DELIMITER $$  
DROP PROCEDURE IF EXISTS `dbcall`.`get_page`$$  
CREATE DEFINER=`root`@`localhost` PROCEDURE `get_page`(  
/**//*Table name*/  
tableName varchar(100),  
/**//*Fileds to display*/  
fieldsNames varchar(100),  
/**//*Page index*/  
pageIndex int,  
/**//*Page Size*/  
pageSize int,   
/**//*Field to sort*/  
sortName varchar(500),  
/**//*Condition*/  
strWhere varchar(500)  
BEGIN   
DECLARE fieldlist varchar(200);   
if fieldsNames=''||fieldsNames=null THEN  
set fieldlist='*';  
set fieldlist=fieldsNames;   
end if;  
if strWhere=''||strWhere=null then  
if sortName=''||sortName=null then   
set @strSQL=concat('SELECT ',fieldlist,' FROM ',tableName,' LIMIT ',(pageIndex-1)*pageSize,',',pageSize);  
set @strSQL=concat('SELECT ',fieldlist,' FROM ',tableName,' ORDER BY ',sortName,' LIMIT ',(pageIndex-1)*pageSize,',',pageSize);   
end if;  
if sortName=''||sortName=null then  
set @strSQL=concat('SELECT ',fieldlist,' FROM ',tableName,' WHERE ',strWhere,' LIMIT ',(pageIndex-1)*pageSize,',',pageSize);  
set @strSQL=concat('SELECT ',fieldlist,' FROM ',tableName,' WHERE ',strWhere,' 
ORDER BY ',sortName,' LIMIT ',(pageIndex-1)*pageSize,',',pageSize);   
end if;  
end if;   
PREPARE stmt1 FROM @strSQL;   
EXECUTE stmt1;  
DEALLOCATE PREPARE stmt1;  
END$$  
DELIMITER ;


创建函数

DELIMITER $$
CREATE FUNCTION my_test_function(quantity INT(10)) RETURNS INT(10) # 创建函数 学习while循环的用法
BEGIN
    WHILE quantity MOD 12 > 0 DO
        SET quantity = quantity + 1;
    END WHILE;
    RETURN quantity;
END $$
DELIMITER ;


#创建函数 返回一个指定长度的随机字符串
CREATE FUNCTION rand_strings(n INT) 
RETURNS VARCHAR(255) #该函数会返回一个字符串
BEGIN 
#chars_str定义一个变量 chars_str,类型是 varchar(100),默认值'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';
 DECLARE chars_str VARCHAR(100) DEFAULT
   'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';
 DECLARE return_str VARCHAR(255) DEFAULT '';
 DECLARE i INT DEFAULT 0;