mysql中函数、存储过程及变量的使用

1. 变量声明与赋值

所有的输入输出变量 ,或者使用中的变量,在使用前,要么使用set 声明,要么使用 declare 声明,或者在变量名字前面加@符号,表示用户自定义变量,否则,会导致变量未定义错误。

单变量赋值

DECLARE @id int(16);
set @a = '12';
set @b = (select count(*) from user);

多变量赋值

DECLARE id int(16);
DECLARE name varchar(128);
select id,name into @id,@name from user where id=1;
select  @id:=id,@name:=name from  user where id=1;

2. 循环的使用

存储过程中的循环使用

DELIMITER $$
DROP PROCEDURE IF EXISTS 'delete_session' $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `delete_session`(IN top int)  
BEGIN  
  
    DECLARE done INT DEFAULT 0;   
    DECLARE temp_id INT;  

    DECLARE cur CURSOR for( SELECT id from user);   
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;  
 
    OPEN cur;  
    FETCH cur INTO temp_id;  
    WHILE done <> 1 DO  
      DELETE FROM user_session WHERE id = temp_id;  
      FETCH cur INTO temp_id;  
    END WHILE;  

    CLOSE cur;  
END $$
DELIMITER; 


函数中的循环使用

-- 获取根分类中的根分类名称
delimiter //
drop function if exists 'getRootCateName' //
CREATE FUNCTION getRootCateName(cate_id varchar(32))
RETURNS varchar(128) DETERMINISTIC
BEGIN
  select pid,category into @p_id,@cate_name from system_category where id=cate_id;
  set @temp_id = @p_id;
  while @temp_id > 0 do
     select pid,category into @p_id,@cate_name from system_category where id=@temp_id;
     set @temp_id = @p_id;
  end while;  
RETURN @cate_name;
end//
delimiter ;

调用

select getRootCateName(28);


3. 选择语句的使用

delimiter //
create function getScoreName(score int(10))
RETURNS varchar(128) DETERMINISTIC
BEGIN
  if score>=90 then 
        set @grade ='A';  
    elseif score<90 and score>=80 then 
        set @grade ='B';  
    elseif score<80 and score>=70 then 
        set @grade ='C';  
    elseif score<70 and score>=60 then 
        set @grade ='D';  
    else 
        set @grade ='E';  
    end if; 
RETURN @grade;
END //
delimiter ;

调用

select getScoreName(91);

4. 分支语句的使用

delimiter //
create function getScoreName2(score int(10))
RETURNS varchar(128) DETERMINISTIC
BEGIN
  SELECT case 
    when score>=90 then '甲' 
    when score>=80 then '乙' 
    when score>=70 then '丙' 
    when score>=60 then '丁' 
    else '差' 
    end as grade  into @commont_grade ;
RETURN @commont_grade;
END //
delimiter ;

调用

select getScoreName2(98);

5. 存储过程输入输出变量的使用

DELIMITER $$  
DROP PROCEDURE IF EXISTS `user_banlance` $$  
CREATE PROCEDURE user_banlance (IN `in_userId` INT , IN `in_banlance` INT, OUT out_code INT, OUT out_message VARCHAR(100))  
_return:BEGIN  
DECLARE _userId bigint(20); 
    DECLARE _banlance int; -- 余额
    DECLARE _verison INT DEFAULT 0;  
    DECLARE _error  INT DEFAULT 0;  
    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET _error = 1;   -- 异常处理
    SET out_code = -1;
    SET out_message = '执行失败';

    #用户账户不存在
    IF NOT EXISTS (select id from user_banlance where id=in_userId) THEN
        SET out_code = 1;
        SET out_message = '用户不存在';
        LEAVE _return;
    END IF;

    select verison,banlance into _verison, _banlance from user_banlance where id=in_userId;

    START TRANSACTION; -- 开启事务 乐观锁的使用
    update user_banlance set banlance = banlance - in_banlance,verison = verison + 1 where id = in_userId and verison = _verison;

    SET @ret_update = ROW_COUNT();
    IF @ret_update = 0 THEN
        ROLLBACK;
        SET out_code = -4;
        SET out_message = '系统错误';
        LEAVE _return;
    END IF;

    IF  _error  <>  0   THEN
        ROLLBACK; 
        SET out_code = -3;
        SET out_message = '系统错误';
        LEAVE _return;
    ELSE    
        COMMIT;
        SET out_code = 1;
        SET out_message = '';
    END IF;

END $$  

DELIMITER ;  

-- 调用  注意输出参数必须是声明的变量,否则会报错

set @b = 0;
set @c = '';
call user_banlance(1,10,@b,@c);

select @b,@c


6. 存储过程的使用(查询游标)

DELIMITER $$  
DROP PROCEDURE IF EXISTS `user_banlance` $$  
CREATE PROCEDURE user_banlance (IN `in_userId` INT , IN `in_banlance` INT)  
BEGIN
  #遍历数据结束标志
  DECLARE done INT DEFAULT FALSE;
  DECLARE _id INT; 
  DECLARE _banlance BIGINT(20);
#游标
  DECLARE cur CURSOR FOR SELECT id,banlance FROM user_banlance where id > in_userId and banlance > in_banlance ;
    #将结束标志绑定到游标
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

-- 建表tb_temp
 DROP TABLE IF EXISTS tb_temp;
 CREATE TEMPORARY TABLE tb_temp(
   `id` int UNSIGNED NOT NULL , 
   `banlance` bigint(20) NOT NULL,
   PRIMARY KEY (`id`)
 ) ENGINE = MYISAM DEFAULT charset = utf8 ;

  -- 打开游标
  OPEN cur;
  -- 开始循环
  read_loop: LOOP
    -- 提取游标里的数据
    FETCH cur INTO _id,_banlance; 
    IF done THEN
      LEAVE read_loop;
    ELSE 
    replace into tb_temp( id ,banlance) values(_id,_banlance);  -- 替换具有唯一索引 和 主键索引的 相同记录
    END IF;
 END LOOP;
 -- 关闭游标 
CLOSE cur; 
select * from tb_temp;
DROP TABLE IF EXISTS tb_temp;
END $$  

DELIMITER ;  

调用

call user_banlance(2,1500);

游标循环的另一种实现方式

-- 打开游标
OPEN cur;
-- 开始循环
REPEAT
-- 提取游标里的数据
    FETCH cur INTO _id,_banlance; 
    IF not done THEN
    insert into tb_temp( id ,banlance) values(_id,_banlance);  -- 替换具有唯一索引 和 主键索引的 相同记录
    END IF;
UNTIL done 
END REPEAT;
 -- 关闭游标 
CLOSE cur; 

[注意]:
[1] fetch 必须在判断之前调用才能避免最后一条记录重复 (最后一次通过循环遍历的时候,“fetch”是失败的,如果这个时候继续处理,你会插入前一次的值。)
[2] drop 和 create 等语句必须在declare 声明语句之后使用,否则会报错

6. 存储过程与函数区别

 调用 存储过程 call procedure_name(arges, arges1...);
      函数 select function_name(arges);

 返回 存储过程可以返回多个值,
     函数只能有一个返回值

猜你喜欢

转载自blog.csdn.net/wujiangwei567/article/details/81281690