zoukankan      html  css  js  c++  java
  • MySQL游标

    1、游标的概念(Cursor)

    一条sql,对应N条资源,取出资源的接口,就是游标,沿着游标,可以一次取出1行。如果开发过安卓的同学应该知道有一个Api是Cursor,也是读取SQLite数据库用的,和这个有点类似。

    2、使用游标的步骤

    (1)声明

    使用declare进行声明

    declare 游标名 cursor for select_statement

    (2)打开游标

    使用open进行打开

    open 游标名

    (3)从游标中取值

    使用fetch进行取值

    fetch 游标名 into var1,var2[,...] --将取到的一行赋值给多个变量

    (4)关闭游标

    使用close关闭游标

    close 游标名

    3、创建一个简单的游标

    需求:从商品表中读取第一行数据

    商品表(goods)数据:

    这里写图片描述

    注意:我这里已经将MySQL的结束标识符改为 $,如果要知道怎么设置为$,请参考我的另一篇文章:MySQL触发器

    定义:

    create procedure p12()
    begin
        /*定义三个变量用于存放商品id,商品名称,商品库存量*/
        declare row_gid int ; 
        declare row_name varchar(20);
        declare row_num int;
        declare getgoods cursor for select gid,name,num from goods;    --定义游标
        open getgoods; --打开游标
        fetch getgoods into row_gid,row_name,row_num;--从游标中取值
        select row_name,row_num; --显示操作
        close getgoods; --关闭游标
    end$

    输出结果:

    这里写图片描述

    4、多次取值操作

    create procedure p13()
    begin
        declare row_gid int ;
        declare row_name varchar(20);
        declare row_num int;
        declare getgoods cursor for select gid,name,num from goods;    
        open getgoods;
        fetch getgoods into row_gid,row_name,row_num;
        select row_name,row_num;
        fetch getgoods into row_gid,row_name,row_num;
        select row_name,row_num;
        fetch getgoods into row_gid,row_name,row_num;
        select row_name,row_num;
        fetch getgoods into row_gid,row_name,row_num;
        select row_name,row_num;
        close getgoods;
    end$

    输出:

    这里写图片描述

    注意:当游标读到末尾,如果继续进行取值操作会发生报错

    5、游标循环表中的所有数据

    (1)使用计数器来循环

    create procedure p14()
    begin 
        declare cnt int default 0;
        declare i int default 0;
        declare row_gid int ;
        declare row_name varchar(20);
        declare row_num int;
        declare getgoods cursor for select gid,name,num from goods;
        select count(*) into cnt from goods;
        open getgoods;
        repeat 
            fetch getgoods into row_gid,row_name,row_num;
        select row_name,row_num;
        set i:= i+1;
        until i >= cnt end repeat;
        close getgoods;
    end$

    输出结果:

    这里写图片描述

    (2)使用越界标志来控制循环

    在mysql cursor中,可以声明declare continue handler来操作1个越界标志

    语法:

    declare continue handler for NOT FOUND statement;

    使用:

    create procedure p15()
    begin
        declare row_gid int ;
        declare row_name varchar(20);
        declare row_num int;
        declare have int default 1;
        declare getgoods cursor for select gid,name,num from goods;
        declare continue handler for NOT FOUND set have:= 0;
        open getgoods;
        repeat 
            fetch getgoods into row_gid,row_name,row_num;
        select row_name,row_num;
        until have = 0 end repeat;
        close getgoods;
    end$

    输出结果:

    这里写图片描述

    注意:这里发生了错误,这里输出了4行数据,而表中只有3行数据,而且还爆出了警告,后面会说怎么结果这个问题。

    程序执行逻辑:

    循环游标->fetch第三条数据->显示->fetch第四条数据->没有数据->设置have=0操作->执行continue Handler->程序不退出,执行显示操作->还是显示第三条数据

    6、continue和exit的区别

    continue:若没有数据返回,程序继续,并将变量IS_FOUND设为0,这种情况是出现在select XX into XXX from tablename的时候发生的。

    exit:若没有数据返回,退出程序,并将变量IS_FOUND设为0,这种情况是出现在select XX into XXX from tablename的时候发生的。

    使用exit来替换continue:
    使用exit就不会出现上面的那种情况了,程序执行逻辑:

    循环游标->fetch到第三条数据->显示->第四次fetch操作->没有数据->设置 have=0操作->程序直接退出exit

    所以就没有显示出第四条数据。

    create procedure p16()
    begin
        declare row_gid int ;
        declare row_name varchar(20);
        declare row_num int;
        declare have int default 1;
        declare getgoods cursor for select gid,name,num from goods;
        declare exit handler for NOT FOUND set have:= 0;
        open getgoods;
        repeat 
            fetch getgoods into row_gid,row_name,row_num;
        select row_name,row_num;
        until have = 0 end repeat;
        close getgoods;
    end$

    输出结果:

    这里写图片描述

    7、正确的游标循环

    在一些特殊的情况中,我们可以读到的数据为空,或者压根sql语句就有错误,我们不能避免出现这种情况,所以我们要正确的使用游标循环操作。

    首先应该创建游标,然后打开游标后,应先手动进行fetch操作获取到一行数据,然后再通过循环,在循环里先做处理内容,后进行fetch操作。这样如果在手动获取数据的期间就没有获得到数据的话,就会执行have = 0,如果是repeat循环,然后进入repeat循环,先输出null数据,最后又进行获取,这样运行到until时就会退出循环;如果是while循环,压根就不进去while循环里,就不会有任何1行输出。

    (1)repeat循环:

    create procedure p17()
    begin
        declare row_gid int;
        declare row_name varchar(20);
        declare row_num int;
        declare have int default 1;
        declare getgoods cursor for select gid,name,num from goods where 0;
        declare continue handler for NOT FOUND set have:= 0;
        open getgoods;
        fetch getgoods into row_gid,row_name,row_num;
        repeat 
        select row_name,row_num;
            fetch getgoods into row_gid,row_name,row_num;
        until have = 0 end repeat;
        close getgoods;
    end$

    输出结果:

    这里写图片描述

    (2)while循环:

    create procedure p18()
    begin
        declare row_gid int;
        declare row_name varchar(20);
        declare row_num int;
        declare have int default 1;
        declare getgoods cursor for select gid,name,num from goods where 0;
        declare continue handler for NOT FOUND set have:= 0;
        open getgoods;
        fetch getgoods into row_gid,row_name,row_num;
        while have = 1 do 
        select row_name,row_num;
            fetch getgoods into row_gid,row_name,row_num;
        end while;
        close getgoods;
    end$

    输出结果:

    这里写图片描述

  • 相关阅读:
    Akka源码分析-Akka Typed
    Akka源码分析-Persistence Query
    5位ID生成方案
    Akka源码分析-Akka-Streams-GraphStage
    akka监控框架设计
    Akka源码分析-Akka-Streams-Materializer(1)
    day30-2FileWriter用数组进行复制文件
    day30-1FileInputStream不用数组进行复制文件
    day30-1FileInputStream用数组进行复制文件
    day29-2在d盘创建文件夹aaa 里面有aaa.txt bbb.txt ddd.txt
  • 原文地址:https://www.cnblogs.com/cnsec/p/13407042.html
Copyright © 2011-2022 走看看