关于Mysql存储过程的一点心得

     最近因为项目需要,写了一个Mysql数据库的存储过程,第一次写Mysql的存储过程还是碰到了不少坑,再此总结一下。

用DECLARE 定义变量或游标时必须放在过程的最前面,在其他执行的sql语句之前,否则会报语法错误

BEGIN
    #局部变量定义 必须放在最前端
    DECLARE i_tn INT DEFAULT 0; #TOTAL_NUMBER
    #定义游标
    DECLARE typeCur CURSOR FOR SELECT types,num FROM certification_type WHERE scbz='0' AND DOMAIN=in_domain AND LEVEL=in_level;

存储过程没有bool或boolean类型,必须使用int类型替代 但可以用true或false来赋值和判断

DECLARE f_done INT DEFAULT FALSE; #CURSOR FLAG
IF NOT f_done THEN 

对于游标可以设置一个handle,在到遍历结果集末尾时触发

#定义游标状态	
DECLARE CONTINUE HANDLER FOR NOT FOUND SET f_done=TRUE;
FETCH sectionCur INTO i_sc,i_rt;
IF NOT f_done THEN 

存储过程中出现异常如何处理,可以做如下定义在,异常时跳出存储过程,并记录错误信息

#定义SQL异常退出 写错误日志
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
    #先记录错误信息 再ROLLBACK 否则将清空错误信息
    GET DIAGNOSTICS CONDITION 1 v_ex_rs=RETURNED_SQLSTATE,v_ex_mt=MESSAGE_TEXT;  
    ROLLBACK;
    INSERT INTO e_log (e_code,e_msg) VALUES (v_ex_rs,v_ex_mt);
END;

使用case语句时,最好都要加上最后的else条件,即使是什么也不做的语句DO NULL,否则在所有的when条件都判断为否时,会报20000, Case not found for CASE statement错误

CASE 
WHEN(SUBSTR(v_sc,1,1)='1' AND i_sn1>0)THEN SET i_sn1=i_sn1-1;IF(i_sn1=0)THEN SET f_change=TRUE;END IF;
WHEN(SUBSTR(v_sc,2,1)='1' AND i_sn2>0)THEN SET i_sn2=i_sn2-1;IF(i_sn2=0)THEN SET f_change=TRUE;END IF;
WHEN(SUBSTR(v_sc,3,1)='1' AND i_sn3>0)THEN SET i_sn3=i_sn3-1;IF(i_sn3=0)THEN SET f_change=TRUE;END IF;
WHEN(SUBSTR(v_sc,4,1)='1' AND i_sn4>0)THEN SET i_sn4=i_sn4-1;IF(i_sn4=0)THEN SET f_change=TRUE;END IF;
WHEN(SUBSTR(v_sc,5,1)='1' AND i_sn5>0)THEN SET i_sn5=i_sn5-1;IF(i_sn5=0)THEN SET f_change=TRUE;END IF;
WHEN(SUBSTR(v_sc,6,1)='1' AND i_sn6>0)THEN SET i_sn6=i_sn6-1;IF(i_sn6=0)THEN SET f_change=TRUE;END IF;
WHEN(SUBSTR(v_sc,7,1)='1' AND i_sn7>0)THEN SET i_sn7=i_sn7-1;IF(i_sn7=0)THEN SET f_change=TRUE;END IF;
WHEN(SUBSTR(v_sc,8,1)='1' AND i_sn8>0)THEN SET i_sn8=i_sn8-1;IF(i_sn8=0)THEN SET f_change=TRUE;END IF;
WHEN(SUBSTR(v_sc,9,1)='1' AND i_sn9>0)THEN SET i_sn9=i_sn9-1;IF(i_sn9=0)THEN SET f_change=TRUE;END IF;
WHEN(SUBSTR(v_sc,10,1)='1' AND i_sn10>0)THEN SET i_sn10=i_sn10-1;IF(i_sn10=0)THEN SET f_change=TRUE;END IF;
ELSE DO NULL;
END CASE;

如何判断查询结果集是否为空

IF(FOUND_ROWS()=0)THEN

如何主动跳出存储过程

leave_procedure: 
BEGIN
    XXXX;
    LEAVE leave_procedure; 

如何操作游标

    DECLARE sectionCur CURSOR FOR SELECT section_code,ratio FROM certification_section;	
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET f_done=TRUE;
    OPEN sectionCur;
	SET f_done=FALSE;
	REPEAT
		FETCH sectionCur INTO i_sc,i_rt;
		IF NOT f_done THEN 
            XXX;
        END IF;
        UNTIL f_done END REPEAT;
	CLOSE sectionCur; 

如何做事务控制

START TRANSACTION;
    XXX;
COMMIT;或ROLLBACK; 结束事务
    

如何动态拼接执行sql语句,其中需要拼接“'”单引号时,需要用"\"做转义,动态执行的语句必须赋值给用户变量@XXX,才能预处理执行

SET v_sql=CONCAT('INSERT INTO user_exam_topic(openid,exam_id,serial_num,topic_id,answer,is_correct) ','SELECT \'',in_openid,'\',',out_id,',0,id,answer,\'1\' FROM topic_library ','WHERE scbz=\'0\' AND types=\'',i_ty,'\'',v_sql_domain,v_sql_level,' ORDER BY RAND() LIMIT ',i_nm);
SET @do_sql=v_sql;
PREPARE stmt FROM @do_sql;  
EXECUTE stmt;   
DEALLOCATE PREPARE stmt; 

如何从动态执行的sql中获取结果 先select into到用户变量@xxx,再从@xxx中读取

SET v_sql=CONCAT('SELECT id,answer,section into @i_id,@v_an,@v_sc FROM topic_library ','WHERE scbz=\'0\' AND types=\'',i_ty,'\'',v_sql_domain,v_sql_level,v_sql_id,v_sql_section,' ORDER BY RAND() LIMIT 1');
SET @do_sql=v_sql;
PREPARE stmt FROM @do_sql;  
EXECUTE stmt;   
DEALLOCATE PREPARE stmt; 
SET i_id=@i_id,v_an=@v_an,v_sc=@v_sc;

如何实现rownum序号列

select (@rowNO := @rowNo+1) AS 序号,a.* from  t_user a,(select @rowNO :=0) b

写在最后,很多东西还有不了解的,需要多查官方文档

https://dev.mysql.com/doc/refman/5.6/en/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值