title : 每日深耕,勤练不缀之游标
面向集合
集合思维更像是从整体的角度来考虑
然后把整个数据集不同的树形进行划分,形成不同的子集合
游标
定义游标
DECLARE cursor_name CURSOR FOR select_statement
打开游标
OPEN cursor_name
从游标中获得数据
FETCH cursor_name INTO var_name
关闭游标
CLOSE cursor_name
释放游标
DEALLOCATE cousor_namec
实战例子
我想用游标来扫描heros数据表中的数据行,然后累计最大生命值
创建一个存储过程 calc_hp_max,然后在存储过程中定义游标cur_gero,使用FETCH获取每一行的具体数值,然后赋给变量hp,再用变量hp_sum做累加求和,最后再输出hp_sum(对于工程师来说简单的累加而已)
CREATE PROCEDURE `calc_hp_max`()
BEGIN
DECLARE hp INT;
DECLARE hp_sum INT DEFAULT 0;
DECLARE done INT DEFAULT false;
DECLARE cur_hero CURSOR FOR SELECT hp_max from heros;
OPEN cur_hero;
read_loop:LOOP
FETCH cur_hero INTO hp;
SET hp_sum =hp_sum + hp;
END LOOP;
CLOSE cur_hero;
SELECT hp_sum;
END
当使用call calc_hp_max()时,会出现1329错误
我们判断游标溢出
当游标溢出时,我们可以制定一个continue事件,这个事件发生后会改变done的值,以此来判断是否溢出
所以我们要在循环中加上对done的判断,如果游标的循环已经结束,就需要跳出read_loop的循环,意思说只要done的值已经变为false,就可以跳出read_loop的循环了
call calc_hp_max()
我们遇到这种问题时,可以用游标来进行转换
CREATE PROCEDURE `alter_attack_growth`()
BEGIN
-- 创建接收游标的变量
DECLARE temp_id INT;
DECLARE temp_growth, temp_max, temp_start, temp_diff FLOAT;
-- 创建结束标志变量
DECLARE done INT DEFAULT false;
-- 定义游标
DECLARE cur_hero CURSOR FOR SELECT id, attack_growth, attack_max, attack_start FROM heros;
-- 指定游标循环结束时的返回值
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = true;
OPEN cur_hero;
FETCH cur_hero INTO temp_id, temp_growth, temp_max, temp_start;
REPEAT
IF NOT done THEN
SET temp_diff = temp_max - temp_start;
IF temp_growth < 5 THEN
IF temp_diff > 200 THEN
SET temp_growth = temp_growth * 1.1;
ELSEIF temp_diff >= 150 AND temp_diff <=200 THEN
SET temp_growth = temp_growth * 1.08;
ELSEIF temp_diff < 150 THEN
SET temp_growth = temp_growth * 1.07;
END IF;
ELSEIF temp_growth >=5 AND temp_growth <=10 THEN
SET temp_growth = temp_growth * 1.05;
END IF;
UPDATE heros SET attack_growth = ROUND(temp_growth,3) WHERE id = temp_id;
END IF;
FETCH cur_hero INTO temp_id, temp_growth, temp_max, temp_start;
UNTIL done = true END REPEAT;
CLOSE cur_hero;
END
SELECT heros.id, heros.attack_growth
FROM heros