1.创建存储过程和函数... 2
1.1 创建存储过程... 2
1.2 创建存储函数... 3
2.变量的使用... 4
2.1 定义变量... 4
2.2 为变量赋值... 4
3.定义条件和处理程序... 4
3.1 定义条件... 5
3.2 定义处理程序... 5
4.光标的使用... 6
4.1声明光标... 6
4.2打开光标... 6
4.3使用光标... 6
4.4 关闭光标... 7
5.流程控制的使用... 7
5.1 IF语句... 7
5.2 CASE语句... 7
5.3 LOOP语句... 8
5.4 LEAVE语句... 8
5.5 ITERATE语句... 8
5.6 REPEAT语句... 9
5.7 WHILE语句... 9
6.调用存储过程和函数... 9
6.1 调用存储过程... 10
6.2 调用存储函数... 10
7.查看存储过程和函数... 10
7.1 SHOW STATUS 语句查看那存储过程和函数的状态... 10
7.2 SHOW CREATE语句查看存储过程和函数的定义... 11
7.3 从information_schema.Routines表中查看存储过程和函数的信息... 12
8.修改存储过程和函数... 12
9.删除存储过程及函数... 13
10.本次实例... 13
存储过程和函数式数据库中定义一些SQL语句的集合,然后直接调用这些存储过程和函数来执行已经定义好的SQL语句。存储过程和函数可以避免开发人员编写相同的SQL语句,而且,存储过程和函数是在mysql服务器中存储和执行的,可以减少客户端和服务器的数据传输。
1.创建存储过程和函数
创建存储过程和函数式指将经常使用的一组SQL语句组合在一起,兵将这些SQL语句当做一个整体存储在mysql服务器中。
1.1 创建存储过程
语法:
Name:'CREATE PROCEDURE'
Description:
Syntax:
CREATE
PROCEDURE sp_name ([proc_parameter[,...]])
[characteristic ...] routine_body
CREATE PROCEDURE表示创建存储过程的关键字
sp_name 表示存储过程的名字
([proc_parameter[,...]]) 表示存储过程的参数列表
[characteristic ...] 表示存储过程的特性
routine_body 表示SQL代码的内容
参数列表:
([proc_parameter[,...]]),由三部分组成,输入输出类型,参数名称,参数类型
[ IN |OUT | INOUT ] param_name type
存储过程特性:
characteristic:
LANGUAGE SQL
| [NOT] DETERMINISTIC
| { CONTAINS SQL | NO SQL | READS SQL DATA |MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
| COMMENT 'string'
一些注释,谁有权执行后面的SQL语句等,都是特性指定的。
实例:
创建一个名为num_from_employee的存储过程.
DELIMITER &&
CREATE PROCEDURE num_from_employee(IN emp_id INT,OUT count_num INT)
READS SQL DATA
BEGIN
SELECT COUNT(*) INTO count_num
FROM test.employee
WHERE d_id=emp_id;
END
&&
DELIMITER ;
mysql> callnum_from_employee(1001,@count_num);
mysql> select @count_num;
1.2 创建存储函数
语法:
CREATE
FUNCTION sp_name ([func_parameter[,...]])
RETURNS type
[characteristic ...] routine_body
CREATE FUNCTION 表示创建存储函数的关键字
RETURNS type 表示返回值的类型,存储过程没有这个。
([func_parameter[,...]]) 表示参数类型,不需要指定输入输出,这里与存储过程的不同。
实例:
下面创建一个名为name_from_employee的存储函数
DELIMITER &&
CREATE FUNCTIONname_from_employee(emp_id INT)
RETURNS VARCHAR(20)
READS SQL DATA
BEGIN
RETURN (SELECT name
FROM employee
WHERE num=emp_id);
END
&&
DELIMITER ;
mysql> selectname_from_employee(1);
2.变量的使用
存储过程和函数中可以定义和使用变量。用户可以使用DECLARE关键字来定义变量。然后可以为变量赋值,这些变量的作用范围是BEGIN...END程序段中。
2.1 定义变量
定义变量mysql_sql,数据类型为INT型,默认值为10
DECLARE my_sql INT DEFAULT 10;
2.2 为变量赋值
方法一:为变量my_sql赋值为30
SET my_sql=30;
方法二:从employee表中查询id为2的记录,将该记录的d_id值赋给变量my_sql
SELECT d_id INTO my_sql FROM employeeWHERE id=2;
3.定义条件和处理程序
定义条件和处理程序是事先定义程序执行过程中可能遇到的问题。并且可以再处理程序中定义解决这些问题的办法。这种方法可以提前预测可能出现的问题,兵提出解决办法。这样可以增强程序处理问题的能力,避免程序异常停止。Mysql中都是通过DECLARE关键字来定义条件和处理程序的。
3.1 定义条件
语法:
DECLAREcondition_name CONDITION FOR condition_value
condition_value:
SQLSTATE[VALUE] sqlstate_value | mysql_error_code
实例:
下面定义“ERROR 1146(42S02)”中这个错误,名称为can_not_find,可以用两种不同的方法定义
方法一:使用sqlstate_value
DECLARE can_not_find CONDITION FORSQLSTATE '42S02';
方法二:使用mysql_error_code
DECLARE can_not_find CONDITION FOR 1146;
3.2 定义处理程序
Name:'DECLARE HANDLER'
Description:
Syntax:
DECLAREhandler_type HANDLER
FOR condition_value [, condition_value] ...
statement
handler_type:
CONTINUE
| EXIT
| UNDO
condition_value:
SQLSTATE [VALUE] sqlstate_value
| condition_name
| SQLWARNING
| NOT FOUND
| SQLEXCEPTION
| mysql_error_code
实例:
下面是定义处理程序的几种方式
方法一:捕获sqlstate_value
DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02' SET @info='CAN NOT FIND';
方法二:捕获mysql_error_code
DECLARE CONTINUE HANDLER FOR 1146 SET@info='CAN NOT FIND';
方法三:先定义条件,然后调用
DECLARE can_not_find CONDITION FOR 1146;
DECLARE CONTINUE HANDLER FOR can_not_find SET @info='CAN NOT FIND';
方法四:使用SQLWARNING
DECLARE EXIT HANDLER FOR SQLWARNING SET @info='ERROR';
方法五:使用NOT FOUND
DECLARE EXIT HANDLER NOT FOUND SET @info='CAN NOT FIND';
方法六:使用SQLEXCEPTION
DECLARE EXIT HANDLER FOR SQLEXCEPTION SET @info='ERROR';
4.光标的使用
查询语句可能查出多条记录,在存储过程和存储函数中使用光标逐条读取查询结果集中的记录。有些书上将光标称为游标。光标的使用包括声明光标、打开光标、使用光标和关闭光标。光标必须声明在处理程序之前,并且声明在变量和条件之后。
4.1声明光标
下面声明一个名为cur_employee的光标
DECLARE cur_employee CURSOR FOR SELECT name,age FROM employee;
4.2打开光标
下面打开一个名为cur_employee的光标
OPEN cur_employee;
4.3使用光标
下面使用一个名为cur_employee的光标,将查询出来的数据存入emp_name和emp_age这两个变量中
FETCH cur_employee INTO emp_name,emp_age;
4.4 关闭光标
下面关闭一个名为cur_employee的光标
CLOSE cur_employee;
5.流程控制的使用
存储过程和存储函数中可以使用流程控制来控制语句的执行。Mysql中可以使用IF语句、CASE语句、LOOP语句、LEAVE语句、ITERATE语句、REPEAT语句、WHILE语句来进行流程控制。
5.1 IF语句
语法:
IFsearch_condition THEN statement_list
{ELSEIF search_condition THENstatement_list}....
{ELSE statement_list}
END IF
示例:
IF age > 20 THEN SET @count1=@count1+1;
ELSEIF age=20 THEN@count2=@count2+1;
ELSE @count3=@count3+1;
END IF;
5.2CASE语句
语法一:
CASEcase_value
WHEN when_value THEN statement_list;
{WHEN when_value THEN statement_list}...
{ELSE statement_list}
END CASE
语法二:
CASE
WHEN search_condition THEN staterment_list
{WHEN search_condition THENstatement_list}....
{ELSE statement_list}
END CASE
示例:
CASE age
WHEN 20 THEN SET@count1=@count1+1;
ELSE SET @count2=@count2+1;
END CASE;
5.3LOOP语句
语法:
[begin_label:]LOOP
statement_list
END LOOP[end_label]
示例:
add_num:LOOP
SET @count=@count+1;
END LOOP add_num;
5.4LEAVE语句
示例:
add_num:LOOP
SET @count=@count+1;
IF @count=100 THEN
LEAVE add_num
END LOOP add_num;
5.5ITERATE语句
add_num:LOOP
SET @count=@count+1;
IF @count=100 THEN
LEAVE add_num
ELSE IF MOD(@count,3)=0 THEN
ITERATE add_num;
SELECT * FROM employee;
END LOOP add_num;
5.6REPEAT语句
语法:
[begin_label:]REPEAT
statement_list
UNTIL search_condition
ENDREPEAT [end_label]
示例:
REPEAT
SET @count=@count+1;
UNTIL @count=100
END REPEAT;
5.7WHILE语句
语法:
[begin_label:] WHILE search_condition DO
statement_list
END WHILE [end_label]
示例:
WHILE @count<100 DO
SET @count=@count+1;
END WHILE;
6.调用存储过程和函数
存储过程和存储函数都是存储在服务器端的SQL语句的集合。要使用这些已经定义好的存储过程和存储函数就必须要通过调用的方式来实现。存储过程是通过CALL语句来调用的。而存储函数的使用方法与mysql内部函数的使用方法是一样的。执行存储过程和存储环视需要拥有EXECUTE权限。EXECUTE权限的信息存储在information_schema数据库下面的USER_PRIVILEGES表中。
6.1 调用存储过程
语法:
CALL sp_name([parameter[,…..]]);
见创建存储过程实例
6.2 调用存储函数
见创建存储函数实例
7.查看存储过程和函数
存储过程和函数创建以后,用户可以查看存储过程和函数的状态和定义。用户可以通过SHOW STATUS语句来查看存储过程和函数的状态,也可以通过SHOW CREATE语句来查看存储过程和函数的定义。用户也可以通过查询information_schema数据库下的Routines表来查看存储过程和函数的信息。
7.1SHOW STATUS 语句查看那存储过程和函数的状态
语法:
SHOW {PROCEDURE|FUNCTION} STATUS [LIKE 'pattern'];
查看存储过程:
mysql> showprocedure status\G
*************************** 1. row ***************************
Db: navi_db
Name:UP_RPT_CLIENT_LOGIN
Type: PROCEDURE
Definer:pgm@localhost
Modified: 2014-06-06 12:26:48
Created: 2014-06-0612:26:48
Security_type: DEFINER
Comment:
character_set_client: utf8
collation_connection: utf8_general_ci
Database Collation:utf8_general_ci
查看存储函数:
mysql> showfunction status\G
*************************** 1. row ***************************
Db: test
Name:name_from_employee
Type: FUNCTION
Definer:root@localhost
Modified: 2014-09-1014:17:22
Created: 2014-09-1014:17:22
Security_type: DEFINER
Comment:
character_set_client: utf8
collation_connection: utf8_general_ci
Database Collation:utf8_general_ci
7.2SHOW CREATE语句查看存储过程和函数的定义
语法:
SHOW CREATE {PROCEDURE|FUNCTION} sp_name;
查看存储过程定义:
mysql> showcreate procedure num_from_employee\G
*************************** 1. row ***************************
Procedure:num_from_employee
sql_mode:
Create Procedure: CREATEDEFINER=`root`@`localhost` PROCEDURE `num_from_employee`(IN emp_id INT,OUTcount_num INT)
READS SQL DATA
BEGIN
SELECT COUNT(*)INTO count_num
FROM test.employee
WHERE d_id=emp_id;
END
character_set_client: utf8
collation_connection: utf8_general_ci
Database Collation:utf8_general_ci
查看存储函数定义:
mysql> showcreate function name_from_employee\G
*************************** 1. row ***************************
Function:name_from_employee
sql_mode:
Create Function: CREATEDEFINER=`root`@`localhost` FUNCTION `name_from_employee`(emp_id INT) RETURNSvarchar(20) CHARSET utf8
READS SQL DATA
BEGIN
RETURN (SELECT name
FROM employee
WHERE num=emp_id);
END
character_set_client: utf8
collation_connection: utf8_general_ci
Database Collation:utf8_general_ci
7.3 从information_schema.Routines表中查看存储过程和函数的信息
语法:
SELECT * FROM information_schema.Routines WHERE ROUTINE_NAME='sp_name';
8.修改存储过程和函数
修改存储过程和函数是指修改已经定义好的存储过程和函数。mysql中通过ALTER PROCEDURE语句来修改存储过程。通过ALTER FUNCTION语句来修改存储函数。
语法:
ALTER {PROCEDURE|FUNCTION} sp_name [characteristic…]
Characteristic:
{CONTAINS SQL|NO SQL|READS SQL DATA|MODIFIES SQL DATA}
|SQL SECURITY {DEFINER|INVOKER}
|COMMENT 'string'
示例修改存储过程:(修改存储函数略)
修改存储过程num_from_employee的定义,将读写权限改为MODIFIES SQL DATA,指明调用者可执行,并添加注释hi feinno.
ALTER PROCEDURE num_from_employee
MODIFIES SQL DATA
SQL SECURITY INVOKER
COMMENT 'hi feinno';
myql>select specific_name,sql_data_access,security_type,routine_commitfrom information_schema.routines where routine_name='num_from_employee';
9.删除存储过程及函数
语法:
DROP {PROCEDURE|FUNCTION} sp_name;
示例删除存储过程及函数
DROP PROCEUDRE test.num_from_employee;
DROP FUNCTION test.name_from_employee;
select count(*) from information_schema.routineswhere routine_name='num_from_employee';
select count(*) frominformation_schema.routines where routine_name='name_from_employee';
10.本次实例
在food表上创建名为food_price_count的存储过程,存储过程food_price_count有三个参数。输入参数为price_info1和price_info2,输出count。存储过程的作用是查询food表中食品单价高于price_info1且低于price_info2的食品种数,然后由count参数输出。并且计算满足条件的单价的总和。
CREATE table food(
id INT(10) PRIMARY KEYNOT NULL,
name VARCHAR(20) NOTNULL,
company VARCHAR(20) NOTNULL,
price DOUBLE NOT NULL,
produce_time YEAR NOTNULL,
valiadity_time INT NOTNULL,
address VARCHAR(50)DEFAULT NULL
);
INSERT INTO foodVALUES(1,'光磊饼干','光磊饼干厂',2.5,'2008',3,'北京'),
(2,'宪政牛奶','宪政牛奶厂',3.5,'2009',3,'秦皇岛'),
(3,'兴周果冻','兴周果冻厂',1.5,'2007',2,'保定'),
(4,'GG咖啡','GG咖啡厂',20,'2002',5,'天津'),
(5,'XX奶糖','XX奶糖厂',14,'2003',3,'上海');
DELIMITER &&
CREATE PROCEDURE food_price_count(IN price_info1 FLOAT,IN price_info2FLOAT,OUT count INT)
READS SQL DATA
BEGIN
DECLARE temp FLOAT;
DECLARE match_price CURSOR FORSELECT price FROM food;
DECLARE EXIT HANDLER FOR NOTFOUND CLOSE match_price;
SET @sum=0;
SELECT COUNT(*) INTO count FROMfood
WHERE price BETWEEN price_info1 AND price_info2;
OPEN match_price;
REPEAT
FETCH match_price INTO temp;
IF temp>price_info1 ANDtemp
THEN SET @sum=@sum+temp;
END IF;
UNTIL 0 END REPEAT;
CLOSE match_price;
END &&
DELIMITER ;
mysql> call food_price_count(2,18,@count);
mysql> select @count,@sum;
解释:
CREATE PROCEDURE food_price_count(IN price_info1 FLOAT,IN price_info2FLOAT,OUT count INT) 创建存储过程。。。
READS SQL DATA 设置为只读数据
BEGIN 语句开始
DECLARE temp FLOAT 定义一个temp变量
DECLARE match_price CURSOR FOR SELECT price FROM food 定义光标,从food表中查询出价格
DECLARE EXIT HANDLER FOR NOT FOUND CLOSE match_price 定义遇到光标关闭的话就结束执行
SET @sum=0 设置一个sum求和,初始值为0
SELECT COUNT(*) INTO count FROM food
WHERE price BETWEEN price_info1 AND price_info2 将查询出来的count(*)赋值给count
OPEN match_price 打开光标
REPEAT 使用repeat循环
FETCH match_price INTO temp 读取光标里面的内容将其放到temp中
IF temp>price_info1 AND temp
THEN SET @sum=@sum+temp 则将sum求和
END IF 结束IF语句
UNTIL 0 END REPEAT 直到光标等于0时,结束repeat循环
CLOSE match_price 关闭光标
END 语句结束