zoukankan      html  css  js  c++  java
  • 游标

    1、游标的作用及属性

    游标的作用就是用于对查询数据库所返回的记录进行遍历,以便进行相应的操作;游标有下面这些属性:

        a、游标是只读的,也就是不能更新它;

        b、游标是不能滚动的,也就是只能在一个方向上进行遍历,不能在记录之间随意进退,不能跳过某些记录;

        c、避免在已经打开游标的表上更新数据。

    2、如何使用游标

    使用游标需要遵循下面步骤:

         a、首先用DECLARE语句声明一个游标              

    [sql] 
     
    1. DECLARE cursor_name CURSOR FOR SELECT_statement;  

    上面这条语句就对,我们执行的select语句返回的记录指定了一个游标   

         b、其次需要使用OPEN语句来打开上面你定义的游标

    [sql] 
     
    1. OPEN cursor_name;  

         c、接下来你可以用FETCH语句来获得下一行数据,并且游标也将移动到对应的记录上(这个就类似java里面的那个iterator)。

    [sql] 
     
    1. FETCH cursor_name INTO variable list;  

         d、然后最后当我们所需要进行的操作都结束后我们要把游标释放掉。

    [sql] 
     
    1. CLOSE cursor_name;  

    在使用游标时需要注意的是,使用定义一个针对NOT FOUND的条件处理函数(condition handler)来避免出现“no data to fetch”这样的错误,条件处理函数就是当某种条件产生时所执行的代码,这里但我们游标指到记录的末尾时,便达到NOT FOUND这样条件,这个时候我们希望继续进行后面的操作,所以我们会在下面的代码中看到一个CONTINUE。

    创建游标

    首先在MySql中创建一张数据表:
    [sql] 
     
    1. CREATE TABLE IF NOT EXISTS `store` (  
    2.   `id` int(11) NOT NULL AUTO_INCREMENT,  
    3.   `name` varchar(20) NOT NULL,  
    4.   `count` int(11) NOT NULL DEFAULT '1',  
    5.   PRIMARY KEY (`id`)  
    6. ) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=7;  
    7.   
    8. INSERT INTO `store` (`id`, `name`, `count`) VALUES  
    9. (1, 'android', 15),  
    10. (2, 'iphone', 14),  
    11. (3, 'iphone', 20),  
    12. (4, 'android', 5),  
    13. (5, 'android', 13),  
    14. (6, 'iphone', 13);  
    我们现在要用存储过程做一个功能,统计iphone的总库存是多少,并把总数输出到控制台。
    [sql] 
     
    1. --在windows系统中写存储过程时,如果需要使用declare声明变量,需要添加这个关键字,否则会报错。  
    2. delimiter //  
    3. drop procedure if exists StatisticStore;  
    4. CREATE PROCEDURE StatisticStore()  
    5. BEGIN  
    6.     --创建接收游标数据的变量  
    7.     declare c int;  
    8.     declare n varchar(20);  
    9.     --创建总数变量  
    10.     declare total int default 0;  
    11.     --创建结束标志变量  
    12.     declare done int default false;  
    13.     --创建游标  
    14.     declare cur cursor for select name,count from store where name = 'iphone';  
    15.     --指定游标循环结束时的返回值  
    16.     declare continue HANDLER for not found set done = true;  
    17.     --设置初始值  
    18.     set total = 0;  
    19.     --打开游标  
    20.     open cur;  
    21.     --开始循环游标里的数据  
    22.     read_loop:loop  
    23.     --根据游标当前指向的一条数据  
    24.     fetch cur into n,c;  
    25.     --判断游标的循环是否结束  
    26.     if done then  
    27.         leave read_loop;    --跳出游标循环  
    28.     end if;  
    29.     --获取一条数据时,将count值进行累加操作,这里可以做任意你想做的操作,  
    30.     set total = total + c;  
    31.     --结束游标循环  
    32.     end loop;  
    33.     --关闭游标  
    34.     close cur;  
    35.   
    36.     --输出结果  
    37.     select total;  
    38. END;  
    39. --调用存储过程  
    40. call StatisticStore();  
    fetch是获取游标当前指向的数据行,并将指针指向下一行,当游标已经指向最后一行时继续执行会造成游标溢出。
    使用loop循环游标时,他本身是不会监控是否到最后一条数据了,像下面代码这种写法,就会造成死循环;
    [sql] 
     
    1. read_loop:loop  
    2. fetch cur into n,c;  
    3. set total = total+c;  
    4. end loop;  
    在MySql中,造成游标溢出时会引发mysql预定义的NOT FOUND错误,所以在上面使用下面的代码指定了当引发not found错误时定义一个continue 的事件,指定这个事件发生时修改done变量的值。
    [sql] 
     
    1. declare continue HANDLER for not found set done = true;  
    所以在循环时加上了下面这句代码:
    [sql] 
     
    1. --判断游标的循环是否结束  
    2. if done then  
    3.     leave read_loop;    --跳出游标循环  
    4. end if;  
    如果done的值是true,就结束循环。继续执行下面的代码。

    使用方式

    游标有三种使用方式:
    第一种就是上面的实现,使用loop循环;
    第二种方式如下,使用while循环:
    [sql] 
     
    1. drop procedure if exists StatisticStore1;  
    2. CREATE PROCEDURE StatisticStore1()  
    3. BEGIN  
    4.     declare c int;  
    5.     declare n varchar(20);  
    6.     declare total int default 0;  
    7.     declare done int default false;  
    8.     declare cur cursor for select name,count from store where name = 'iphone';  
    9.     declare continue HANDLER for not found set done = true;  
    10.     set total = 0;  
    11.     open cur;  
    12.     fetch cur into n,c;  
    13.     while(not done) do  
    14.         set total = total + c;  
    15.         fetch cur into n,c;  
    16.     end while;  
    17.       
    18.     close cur;  
    19.     select total;  
    20. END;  
    21.   
    22. call StatisticStore1();  
    第三种方式是使用repeat执行:
    [sql] 
     
    1. drop procedure if exists StatisticStore2;  
    2. CREATE PROCEDURE StatisticStore2()  
    3. BEGIN  
    4.     declare c int;  
    5.     declare n varchar(20);  
    6.     declare total int default 0;  
    7.     declare done int default false;  
    8.     declare cur cursor for select name,count from store where name = 'iphone';  
    9.     declare continue HANDLER for not found set done = true;  
    10.     set total = 0;  
    11.     open cur;  
    12.     repeat  
    13.     fetch cur into n,c;  
    14.     if not done then  
    15.         set total = total + c;  
    16.     end if;  
    17.     until done end repeat;  
    18.     close cur;  
    19.     select total;  
    20. END;  
    21.   
    22. call StatisticStore2();  

    游标嵌套

    在mysql中,每个begin end 块都是一个独立的scope区域,由于MySql中同一个error的事件只能定义一次,如果多定义的话在编译时会提示Duplicate handler declared in the same block。
    [sql] 
     
    1. drop procedure if exists StatisticStore3;  
    2. CREATE PROCEDURE StatisticStore3()  
    3. BEGIN  
    4.     declare _n varchar(20);  
    5.     declare done int default false;  
    6.     declare cur cursor for select name from store group by name;  
    7.     declare continue HANDLER for not found set done = true;  
    8.     open cur;  
    9.     read_loop:loop  
    10.     fetch cur into _n;  
    11.     if done then  
    12.         leave read_loop;  
    13.     end if;  
    14.     begin  
    15.         declare c int;  
    16.         declare n varchar(20);  
    17.         declare total int default 0;  
    18.         declare done int default false;  
    19.         declare cur cursor for select name,count from store where name = 'iphone';  
    20.         declare continue HANDLER for not found set done = true;  
    21.         set total = 0;  
    22.         open cur;  
    23.         iphone_loop:loop  
    24.         fetch cur into n,c;  
    25.         if done then  
    26.             leave iphone_loop;  
    27.         end if;  
    28.         set total = total + c;  
    29.         end loop;  
    30.         close cur;  
    31.         select _n,n,total;  
    32.     end;  
    33.     begin  
    34.             declare c int;  
    35.             declare n varchar(20);  
    36.             declare total int default 0;  
    37.             declare done int default false;  
    38.             declare cur cursor for select name,count from store where name = 'android';  
    39.             declare continue HANDLER for not found set done = true;  
    40.             set total = 0;  
    41.             open cur;  
    42.             android_loop:loop  
    43.             fetch cur into n,c;  
    44.             if done then  
    45.                 leave android_loop;  
    46.             end if;  
    47.             set total = total + c;  
    48.             end loop;  
    49.             close cur;  
    50.         select _n,n,total;  
    51.     end;  
    52.     begin  
    53.       
    54.     end;  
    55.     end loop;  
    56.     close cur;  
    57. END;  
    58.   
    59. call StatisticStore3();  
    上面就是实现一个嵌套循环,当然这个例子比较牵强。凑合看看就行。。

    动态SQL

    Mysql 支持动态SQL的功能,
    
    [sql] 
     
    1. set @sqlStr='select * from table where condition1 = ?';  
    2. prepare s1 for @sqlStr;  
    3. --如果有多个参数用逗号分隔  
    4. execute s1 using @condition1;  
    5. --手工释放,或者是 connection 关闭时, server 自动回收  
    6. deallocate prepare s1;  
  • 相关阅读:
    boost::asio在VS2008下的编译错误
    Java集合框架——接口
    ACM POJ 3981 字符串替换(简单题)
    ACM HDU 1042 N!(高精度计算阶乘)
    OneTwoThree (Uva)
    ACM POJ 3979 分数加减法(水题)
    ACM HDU 4004 The Frog's Games(2011ACM大连赛区第四题)
    Hexadecimal View (2011ACM亚洲大连赛区现场赛D题)
    ACM HDU 4002 Find the maximum(2011年大连赛区网络赛第二题)
    ACM HDU 4001 To Miss Our Children Time (2011ACM大连赛区网络赛)
  • 原文地址:https://www.cnblogs.com/GotoJava/p/7424057.html
Copyright © 2011-2022 走看看