语法:
CREATE PROCEDURE proc_name ([proc_parameter]) [characteristics...] body
讲解:
CREATE PROCEDURE:创建存储过程关键字
proc_name:存储过程名称
proc_parameter:参数列表,可选,格式:[IN | OUT | INOUT] param_name type
IN:输入参数
OUT:输出参数
INOUT:既可以输入也可以输出
param_name:参数名称
type:参数类型,MySQL中的任意类型,如varchar等
characteristics:指定存储过程特性,取值如下:
LANGUAGE SQL:说明body部分由SQL语句组成,LANGUAGE可选值只有SQL
[NOT] DETERMINISTIC:指明存储过程执行结果是否确定。默认值:NOT DETERMINISTIC
DETERMINISTIC:结果确定,每次执行存储过程时,相同的输入会得到相同的输出
NOT DETERMINISTIC:结果不确定,相同输入可能得到不同输出。
{CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA}:指定子程序使用存储过程的限制。默认值:CONTAINS SQL
CONTAINS SQL:说明子程序包含SQL语句,但是不包含写数据语句
NO SQL:说明子程序不包含SQL语句
READS SQL DATA:说明子程序包含读数据读数据语句
MODIFIES SQL DATA:说明子程序包含写数据语句
SQL SECURITY {DEFINER | INVOKER}:指明谁有权限执行,默认值:DEFINER
DEFINER:只有定义者才能执行
INVOKER:拥有权限的调用者才可以执行
COMMNET:注释信息
语法:
CALL proc_name ([parameter[,...]])
案例:
DELIMITER $$
CREATE PROCEDURE proc_countByName(IN uname VARCHAR(100), OUT total INT)
BEGIN
SELECT COUNT(*) INTO total FROM njit_user WHERE NAME LIKE CONCAT('%', uname, '%');
END $$
语法:
DROP {PROCEDURE | FUNCTION} [IF EXISTS] proc_name
删除:
DROP PROCEDURE proc_countByName;
DROP PROCEDURE IF EXISTS proc_countByName;
语法:
ALTER {PROCEDURE | FUNCTION} proc_or_func [characterustic...]
说明:
{CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA}:指定子程序使用存储过程的限制。
CONTAINS SQL:说明子程序包含SQL语句,但是不包含写数据语句
NO SQL:说明子程序不包含SQL语句
READS SQL DATA:说明子程序包含读数据读数据语句
MODIFIES SQL DATA:说明子程序包含写数据语句
SQL SECURITY {DEFINER | INVOKER}:指明谁有权限执行,默认值:DEFINER
DEFINER:只有定义者才能执行
INVOKER:拥有权限的调用者才可以执行
COMMNET:注释信息
语法:
SHOW {PROCEDURE | FUNCTION} STATUS [LIKE 'parttern']
说明:
这个语句是MySQL的扩展,它返回子程序的特征,如数据库、名字、类型、创建者及创建和修改日期。如果没有指定样式,根据使用的语句,所有存储程序或存储函数的信息都被列出。PROCEDURE和FUNCTION分别表示查看存储过程和函数;LIKE语句表示匹配存储过程或函数名称。
案例:
SHOW PROCEDURE STATUS LIKE 'proc_%';
### 创建存储过程
-- 定义结束符[为了PROCEDURE的结束符与mysql的普通语句不同]
delimiter //
-- 如果该储存过程存在就删除
DROP PROCEDURE IF EXISTS in_param;
-- 创建一个储存过程[in_param],需要传入参数inParam
CREATE PROCEDURE in_param(INOUT inParam VARCHAR(50))
-- 开始标识符
BEGIN
-- 定义变量
DECLARE var_param1 VARCHAR(50) DEFAULT "自定义变量默认值var_param1";
-- 获取数据值
SELECT var_param1;
-- 重新改变数据值
SET var_param1='改变自定义的属性值';
-- 获取数据值
SELECT var_param1;
-- 重新赋值
select "运行into储存值" into intoParam;
select intoParam;
-- 语句执行结束符
END //
-- 重新改变数据的结束的标识符
delimiter ;
### 调用存储过程
语法:call sp_name()
注意:存储过程名称后面必须加括号,哪怕该存储过程没有参数传递
### 删除存储过程
语法:drop procedure sp_name
注意:不能在一个存储过程中删除另一个存储过程,只能调用另一个存储过程
-- 定义结束符[为了PROCEDURE的结束符与mysql的普通语句不同]
delimiter //
-- 如果该储存过程存在就删除
DROP PROCEDURE IF EXISTS in_param;
-- 创建一个储存过程[in_param],需要传入参数inParam
CREATE PROCEDURE in_param(INOUT inParam VARCHAR(50))
-- 开始标识符
BEGIN
-- 定义变量
DECLARE var_param1 VARCHAR(50) DEFAULT "自定义变量默认值var_param1";
DECLARE intoParam VARCHAR(50) DEFAULT "自定义变量默认值intoParam";
-- 获取数据值
SELECT var_param1;
SELECT inParam;
-- 重新改变数据值
SET var_param1='改变自定义的属性值';
SET inParam='传入值的修改';
-- 获取数据值
SELECT var_param1;
SELECT inParam;
-- 重新赋值
select "运行into储存值" into intoParam;
select intoParam;
-- 语句执行结束符
END //
-- 重新改变数据的结束的标识符
delimiter ;
-- 调用储存过程[储存过程是传入的参数当我们select @inParamStr输出的是原始值,而不是过程内部修改之后的值,如果我们更改参数类型为inout,则会输出]
set @inParamStr="传入参数";
CALL in_param(@inParamStr);
select @inParamStr;
变量的定义
DECLARE [相同属性的变量x ......] VARCHAR(50) DEFAULT "默认的初始化值";
改变变量值
SET x= "修改之后的值";
改变变量值
select "查询改变之后的值" into x;
变量范围(作用域)
一个变量有自己的范围(作用域),它用来定义它的生命周期。 如果在存储过程中声明一个变量,那么当达到存储过程的END语句时,它将超出范围,因此在其它代码块中无法访问。
如果您在BEGIN END块内声明一个变量,那么如果达到END,它将超出范围。 可以在不同的作用域中声明具有相同名称的两个或多个变量,因为变量仅在自己的作用域中有效。 但是,在不同范围内声明具有相同名称的变量不是很好的编程习惯。
以@符号开头的变量是会话变量。直到会话结束前它可用和可访问。
#定义条件
语法:DECLARE cond_name CONDITION FOR [cond_type]
解析:[cond_type]:SQLSTATE [VALUE] sqlstate_value(可选项) | mysql_erroe_code(可选项)
cond_name:条件名称
cond_type:条件类型,用于定义MySQL的错误,SQLSTATE是长度为5的字符串类型的错误代码;mysql_error_code是数值类型的错误代码。例如ERROR 1142(42000),sql_state_value的值是'42000',mysql_error_code的值是1142。
示例:
-- 使用SQLSTATE
DECLARE cond_error CONDITION FOR SQLSTATE '42000';
-- 使用mysql_error_code
DECLARE cond_error CONDITION FOR 1148;
#定义处理程序
语法:DECLARE handler_type HANDLER FOR condition_value[,...] sp_statement
解析:handler_type:指定错误处理方式
CONTINUE:遇到错误不处理,继续执行
EXIT:遇到错误立即退出
UNDO:遇到错误撤回之前的操作
condition_value:表示错误类型
SQLSTATE [VALUE] sqlstate_value:包含5个字符的字符串错误值
mysql_error_code:数值类型的错误代码
cond_name:定义条件的名称,见第一节
SQLWARNING:匹配所有以01开头的SQLSTATE错误代码
NOT FOUND:匹配所有以02开头的SQLSTATE错误代码
SQL EXCEPTION:匹配所有没有被SQLWARNING或NOT FOUND捕获的SQLSTATE错误代码
sp_statement: 程序语句段
程序语句段,表示在遇到定义的错误时执行的存储过程或函数。
示例:
-- 捕获SQLSTATE
DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02' SET @info='NO_SUCH_TABLE';
-- 捕获mysql_error_code
DECLARE CONTINUE HANDLER FOR SQLSTATE '1146' SET @info='NO_SUCH_TABLE' ;
-- 捕获定义条件
DECLARE no_such_table CONDITION FOR 1146;
DECLARE CONTINUE HANDLER FOR no_such_table SET @info='NO_SUCH_TABLE';
-- 捕获SQLWARNING
DECLARE EXIT HANDLER FOR SQLWARNING set @info='ERROR';
-- 捕获NOT FOUND
DECLARE EXIT HANDLER FOR NOT FOUND set @info='NO_SUCH_TABLE';
-- 捕获SQLEXCEPTION
DECLARE EXIT HANDLER FOR SQLEXCEPTION set @info='ERROR';
-- 捕获所有异常
DECLARE EXIT HANDLER FOR SQLWARNING, NOT FOUND,SQLEXCEPTION BEGIN ... END;
#存储过程示例
DELIMITER $$
CREATE PROCEDURE proc_del_user(IN uid INT, OUT rowCount INT, OUT msg VARCHAR(200))
BEGIN
-- 出错标记
DECLARE t_error INT DEFAULT 0;
-- 定义出错处理程序
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET t_error = 1;
-- 删除用户
DELETE FROM t_user WHERE id = uid;
-- 异常处理
IF t_error = 0 THEN
SET msg = 'success';
ELSE
SET msg = 'error';
END IF;
-- 设置真正影响行数的行数,修改了但是没有修改值都不计入
SET rowCount = ROW_COUNT();
SELECT rowCount, msg;
END $$
-- 调用储存过程
CALL proc_del_user(1, @rowCount, @msg);
SELECT @rowCount, @msg;
光标:查询语句可能查询出多条记录,在存储过程和函数中使用光标来逐条读取查询结果集中的记录
步骤:声明光标->打开光标->使用光标->关闭光标;
光标必须声明在处理程序之前,并且声明在变量和条件之后。
语法:
声明光标:DECLARE cursor_name CURSOR FOR select_statement(sql命令);
cursor_name参数表示光标的名称;select_statement参数表示SELECT语句的内容,返回一个用于创建光标的结果集
打开光标:OPEN cursor_name;
cursor_name参数表示光标的名称。
使用光标:FETCH cur_employee INTO var_name[,var_name…] ;
cursor_name参数表示光标的名称;var_name参数表示将光标中的SELECT语句查询出来的信息存入该参数中。var_name必须在声明光标之前就定义好
关闭光标:CLOSE cursor_name ;
cursor_name参数表示光标的名称。关闭之后就不能使用FETCH来使用光标了
例子:
begin
##定义变量
declare my_id varchar(32);
declare my_name varchar(50);
DECLARE done INT DEFAULT FALSE;
#创建游标并存储数据,
DECLARE My_Cursor CURSOR FOR ( SELECT tid,tname FROM `teacher` );
#游标中内容执行完设置done为1
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
#设置手动提交
set autocommit=0;
#打开游标
OPEN My_Cursor;
#执行循环
myLoop: LOOP
#判断是否结束循环
IF done THEN
LEAVE myLoop;
END IF;
#取出游标中的值
FETCH My_Cursor into my_id,my_name;
#更新数据
UPDATE course SET cname = my_name WHERE teacher_id = my_id ;
END LOOP myLoop;
#释放游标
CLOSE My_Cursor;
#提交
COMMIT;
END
流程控制:[IF语句、CASE语句、LOOP语句、LEAVE语句、ITERATE语句、REPEAT语句、WHILE]
语法:
IF语句:[类似于java的if-else if-else]search_condition参数表示条件判断语句;statement_list参数表示不同条件的执行语句[MYSQL还有一个IF()函数,他不同于这里描述的IF语句]
语法:
IF search_condition THEN statement_list
[ELSEIF search_condition THEN statement_list] ...
[ELSE statement_list]
END IF
案例:
IF age>20 THEN SET @count1=@count1+1;
ELSEIF age=20 THEN SET @count2=@count2+1;
ELSE SET @count3=@count3+1;
END IF;
CASE语句:[类似于java的switch]case_value参数表示条件判断的变量;when_value参数表示变量的取值;statement_list参数表示不同when_value值的执行语句
语法:
CASE case_value
WHEN when_value THEN statement_list
[WHEN when_value THEN statement_list] ...
[ELSE statement_list]
END CASE
案例:
CASE age
WHEN 20 THEN SET @count1=@count1+1;
ELSE SET @count2=@count2+1;
END CASE ;
CASE另一种写法:[类似于java的switch]CASE search_condition参数表示条件判断语句;statement_list参数表示不同条件的执行语句;
语法:
WHEN search_condition THEN statement_list
[WHEN search_condition THEN statement_list] ...
[ELSE statement_list]
END CASE
案例:
CASE
WHEN age=20 THEN SET @count1=@count1+1;
ELSE SET @count2=@count2+1;
END CASE;
注意:注意:这里的CASE语句和“控制流程函数”里描述的SQL CASE表达式的CASE语句有轻微不同。这里的CASE语句不能有ELSE NULL子句并且用END CASE替代END来终止!!
LOOP语句:[类似于java的for]LOOP语句可以使某些特定的语句重复执行,实现一个简单的循环,但是LOOP语句本身没有停止循环的语句,必须是遇到LEAVE语句等才能停止循环
语法:begin_label参数和end_label参数分别表示循环开始和结束的标志,这两个标志必须相同,而且都可以省略;statement_list参数表示需要循环执行的语句
[begin_label:] LOOP
statement_list
END LOOP [end_label]
案例:因为没有跳出循环的语句,这个循环成了一个死循环
add_num: LOOP
SET @count=@count+1;
END LOOP add_num ;
LEAVE语句:[类似于java的return]LEAVE语句主要用于跳出循环控制
语法:label参数表示循环的标志
LEAVE label
案例:
add_num: LOOP
SET @count=@count+1;
IF @count=100 THEN
LEAVE add_num ;
END LOOP add_num ;
ITERATE语句:[类似于java的continue]ITERATE语句也是用来跳出循环的语句。但是,ITERATE语句是跳出本次循环,然后直接进入下一次循环;ITERATE语句只可以出现在LOOP、REPEAT、WHILE语句内
语法:label参数表示循环的标志
ITERATE label
案例:
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 ;
REPEAT语句:[类似于Java的do-while]REPEAT语句是有条件控制的循环语句。当满足特定条件时,就会跳出循环语句
语法:statement_list参数表示循环的执行语句;search_condition参数表示结束循环的条件,满足该条件时循环结束
[begin_label:] REPEAT
statement_list
UNTIL search_condition
END REPEAT [end_label]
案例:
REPEAT
SET @count=@count+1;
UNTIL @count=100
END REPEAT ;
WHILE语句:[类似于Java的while]WHILE语句也是有条件控制的循环语句。但WHILE语句和REPEAT语句是不一样的。WHILE语句是当满足条件时,执行循环内的语句
语法:search_condition参数表示循环执行的条件,满足该条件时循环执行,statement_list参数表示循环的执行语句
[begin_label:] WHILE search_condition DO
statement_list
END WHILE [end_label]
案例:
WHILE @count<100 DO
SET @count=@count+1;
END WHILE ;