• Oracle 游标使用全解(转)


    转自:http://www.cnblogs.com/sc-xx/archive/2011/12/03/2275084.html

    这个文档几乎包含了oracle游标使用的方方面面,全部通过了测试

      1 -- 声明游标;CURSOR cursor_name IS select_statement
      2 
      3 --For 循环游标
      4 --(1)定义游标
      5 --(2)定义游标变量
      6 --(3)使用for循环来使用这个游标
      7 declare
      8        --类型定义
      9        cursor c_job
     10        is
     11        select empno,ename,job,sal
     12        from emp
     13        where job='MANAGER';
     14        --定义一个游标变量v_cinfo c_emp%ROWTYPE ,该类型为游标c_emp中的一行数据类型
     15        c_row c_job%rowtype;
     16 begin
     17        for c_row in c_job loop
     18          dbms_output.put_line(c_row.empno||'-'||c_row.ename||'-'||c_row.job||'-'||c_row.sal);
     19        end loop;
     20 end;
     21 
     22 
     23       
     24 --Fetch游标
     25 --使用的时候必须要明确的打开和关闭
     26 
     27 declare 
     28        --类型定义
     29        cursor c_job
     30        is
     31        select empno,ename,job,sal
     32        from emp
     33        where job='MANAGER';
     34        --定义一个游标变量
     35        c_row c_job%rowtype;
     36 begin
     37        open c_job;
     38          loop
     39            --提取一行数据到c_row
     40            fetch c_job into c_row;
     41            --判读是否提取到值,没取到值就退出
     42            --取到值c_job%notfound 是false 
     43            --取不到值c_job%notfound 是true
     44            exit when c_job%notfound;
     45             dbms_output.put_line(c_row.empno||'-'||c_row.ename||'-'||c_row.job||'-'||c_row.sal);
     46          end loop;
     47        --关闭游标
     48       close c_job;
     49 end;
     50 
     51 --1:任意执行一个update操作,用隐式游标sql的属性%found,%notfound,%rowcount,%isopen观察update语句的执行情况。
     52        begin
     53          update emp set ENAME='ALEARK' WHERE EMPNO=7469;
     54          if sql%isopen then
     55            dbms_output.put_line('Openging');
     56            else
     57              dbms_output.put_line('closing');
     58              end if;
     59           if sql%found then
     60             dbms_output.put_line('游标指向了有效行');--判断游标是否指向有效行
     61             else
     62               dbms_output.put_line('Sorry');
     63               end if;
     64               if sql%notfound then
     65                 dbms_output.put_line('Also Sorry');
     66                 else
     67                   dbms_output.put_line('Haha');
     68                   end if;
     69                    dbms_output.put_line(sql%rowcount);
     70                    exception 
     71                      when no_data_found then
     72                        dbms_output.put_line('Sorry No data');
     73                        when too_many_rows then
     74                          dbms_output.put_line('Too Many rows');
     75                          end;
     76 declare
     77        empNumber emp.EMPNO%TYPE;
     78        empName emp.ENAME%TYPE;
     79        begin
     80          if sql%isopen then
     81            dbms_output.put_line('Cursor is opinging');
     82            else
     83              dbms_output.put_line('Cursor is Close');
     84              end if;
     85              if sql%notfound then
     86                dbms_output.put_line('No Value');
     87                else
     88                  dbms_output.put_line(empNumber);
     89                  end if;
     90                  dbms_output.put_line(sql%rowcount);
     91                  dbms_output.put_line('-------------');
     92                  
     93                  select EMPNO,ENAME into  empNumber,empName from emp where EMPNO=7499;
     94                  dbms_output.put_line(sql%rowcount);
     95                  
     96                 if sql%isopen then
     97                 dbms_output.put_line('Cursor is opinging');
     98                 else
     99                 dbms_output.put_line('Cursor is Closing');
    100                 end if;
    101                  if sql%notfound then
    102                  dbms_output.put_line('No Value');
    103                  else
    104                  dbms_output.put_line(empNumber);
    105                  end if;
    106                  exception 
    107                    when no_data_found then
    108                      dbms_output.put_line('No Value');
    109                      when too_many_rows then
    110                        dbms_output.put_line('too many rows');
    111                        end;
    112                    
    113                  
    114        
    115 --2,使用游标和loop循环来显示所有部门的名称
    116 --游标声明
    117 declare 
    118        cursor csr_dept
    119        is
    120        --select语句
    121        select DNAME
    122        from Depth;
    123        --指定行指针,这句话应该是指定和csr_dept行类型相同的变量
    124        row_dept csr_dept%rowtype;
    125 begin
    126        --for循环
    127        for row_dept in csr_dept loop
    128            dbms_output.put_line('部门名称:'||row_dept.DNAME);
    129        end loop;
    130 end;
    131 
    132 
    133 --3,使用游标和while循环来显示所有部门的的地理位置(用%found属性)
    134 declare
    135        --游标声明
    136        cursor csr_TestWhile
    137        is
    138        --select语句
    139        select  LOC
    140        from Depth;
    141        --指定行指针
    142        row_loc csr_TestWhile%rowtype;
    143 begin
    144   --打开游标
    145        open csr_TestWhile;
    146        --给第一行喂数据
    147        fetch csr_TestWhile into row_loc;
    148        --测试是否有数据,并执行循环
    149          while csr_TestWhile%found loop
    150            dbms_output.put_line('部门地点:'||row_loc.LOC);
    151            --给下一行喂数据
    152            fetch csr_TestWhile into row_loc;
    153          end loop;
    154        close csr_TestWhile;
    155 end; 
    156 select * from emp
    157 
    158 
    159 
    160        
    161 --4,接收用户输入的部门编号,用for循环和游标,打印出此部门的所有雇员的所有信息(使用循环游标)
    162 --CURSOR cursor_name[(parameter[,parameter],...)] IS select_statement;
    163 --定义参数的语法如下:Parameter_name [IN] data_type[{:=|DEFAULT} value]  
    164 
    165 declare 
    166       CURSOR 
    167       c_dept(p_deptNo number)
    168       is
    169       select * from emp where emp.depno=p_deptNo;
    170       r_emp emp%rowtype;
    171 begin
    172         for r_emp in c_dept(20) loop
    173             dbms_output.put_line('员工号:'||r_emp.EMPNO||'员工名:'||r_emp.ENAME||'工资:'||r_emp.SAL);
    174         end loop;
    175 end;
    176 select * from emp   
    177 --5:向游标传递一个工种,显示此工种的所有雇员的所有信息(使用参数游标)
    178 declare 
    179        cursor
    180        c_job(p_job nvarchar2)
    181        is 
    182        select * from emp where JOB=p_job;
    183        r_job emp%rowtype;
    184 begin 
    185        for r_job in c_job('CLERK') loop
    186            dbms_output.put_line('员工号'||r_job.EMPNO||' '||'员工姓名'||r_job.ENAME);
    187         end loop;
    188 end;
    189 SELECT * FROM EMP
    190 
    191 --6:用更新游标来为雇员加佣金:(用if实现,创建一个与emp表一摸一样的emp1表,对emp1表进行修改操作),并将更新前后的数据输出出来 
    192 --http://zheng12tian.iteye.com/blog/815770 
    193         create table emp1 as select * from emp;
    194         
    195 declare
    196         cursor
    197         csr_Update
    198         is
    199         select * from  emp1 for update OF SAL;
    200         empInfo csr_Update%rowtype;
    201         saleInfo  emp1.SAL%TYPE;
    202 begin
    203     FOR empInfo IN csr_Update LOOP
    204       IF empInfo.SAL<1500 THEN
    205         saleInfo:=empInfo.SAL*1.2;
    206        elsif empInfo.SAL<2000 THEN
    207         saleInfo:=empInfo.SAL*1.5;
    208         elsif empInfo.SAL<3000 THEN
    209         saleInfo:=empInfo.SAL*2;
    210       END IF;
    211       UPDATE emp1 SET SAL=saleInfo WHERE CURRENT OF csr_Update;
    212      END LOOP;
    213 END;
    214 
    215 --7:编写一个PL/SQL程序块,对名字以‘A’或‘S’开始的所有雇员按他们的基本薪水(sal)的10%给他们加薪(对emp1表进行修改操作)
    216 declare 
    217      cursor
    218       csr_AddSal
    219      is
    220       select * from emp1 where ENAME LIKE 'A%' OR ENAME LIKE 'S%' for update OF SAL;
    221       r_AddSal csr_AddSal%rowtype;
    222       saleInfo  emp1.SAL%TYPE;
    223 begin
    224       for r_AddSal in csr_AddSal loop
    225           dbms_output.put_line(r_AddSal.ENAME||'原来的工资:'||r_AddSal.SAL);
    226           saleInfo:=r_AddSal.SAL*1.1;
    227           UPDATE emp1 SET SAL=saleInfo WHERE CURRENT OF csr_AddSal;
    228       end loop;
    229 end;
    230 --8:编写一个PL/SQL程序块,对所有的salesman增加佣金(comm)500
    231 declare
    232       cursor
    233           csr_AddComm(p_job nvarchar2)
    234       is
    235           select * from emp1 where   JOB=p_job FOR UPDATE OF COMM;
    236       r_AddComm  emp1%rowtype;
    237       commInfo emp1.comm%type;
    238 begin
    239     for r_AddComm in csr_AddComm('SALESMAN') LOOP
    240         commInfo:=r_AddComm.COMM+500;
    241          UPDATE EMP1 SET COMM=commInfo where CURRENT OF csr_AddComm;
    242     END LOOP;
    243 END;
    244 
    245 --9:编写一个PL/SQL程序块,以提升2个资格最老的职员为MANAGER(工作时间越长,资格越老)
    246 --(提示:可以定义一个变量作为计数器控制游标只提取两条数据;也可以在声明游标的时候把雇员中资格最老的两个人查出来放到游标中。)
    247 declare
    248     cursor crs_testComput
    249     is
    250     select * from emp1 order by HIREDATE asc;
    251     --计数器
    252     top_two number:=2;
    253     r_testComput crs_testComput%rowtype;
    254 begin
    255     open crs_testComput;
    256        FETCH crs_testComput INTO r_testComput;
    257           while top_two>0 loop
    258              dbms_output.put_line('员工姓名:'||r_testComput.ENAME||' 工作时间:'||r_testComput.HIREDATE);
    259              --计速器减一
    260              top_two:=top_two-1;
    261              FETCH crs_testComput INTO r_testComput;
    262            end loop;
    263      close crs_testComput;
    264 end;
    265     
    266 
    267 --10:编写一个PL/SQL程序块,对所有雇员按他们的基本薪水(sal)的20%为他们加薪,
    268 --如果增加的薪水大于300就取消加薪(对emp1表进行修改操作,并将更新前后的数据输出出来) 
    269 declare
    270     cursor
    271         crs_UpadateSal
    272     is
    273         select * from emp1 for update of SAL;
    274         r_UpdateSal crs_UpadateSal%rowtype;
    275         salAdd emp1.sal%type;
    276         salInfo emp1.sal%type;
    277 begin
    278         for r_UpdateSal in crs_UpadateSal loop
    279            salAdd:= r_UpdateSal.SAL*0.2;
    280            if salAdd>300 then
    281              salInfo:=r_UpdateSal.SAL;
    282               dbms_output.put_line(r_UpdateSal.ENAME||':  加薪失败。'||'薪水维持在:'||r_UpdateSal.SAL);
    283              else 
    284               salInfo:=r_UpdateSal.SAL+salAdd;
    285               dbms_output.put_line(r_UpdateSal.ENAME||':  加薪成功.'||'薪水变为:'||salInfo);
    286            end if;
    287            update emp1 set SAL=salInfo where current of crs_UpadateSal;
    288         end loop;
    289 end;
    290      
    291 --11:将每位员工工作了多少年零多少月零多少天输出出来   
    292 --近似
    293   --CEIL(n)函数:取大于等于数值n的最小整数
    294   --FLOOR(n)函数:取小于等于数值n的最大整数
    295   --truc的用法 http://publish.it168.com/2005/1028/20051028034101.shtml
    296 declare
    297   cursor
    298    crs_WorkDay
    299    is
    300    select ENAME,HIREDATE, trunc(months_between(sysdate, hiredate) / 12) AS SPANDYEARS,
    301        trunc(mod(months_between(sysdate, hiredate), 12)) AS months,
    302        trunc(mod(mod(sysdate - hiredate, 365), 12)) as days
    303    from emp1;
    304   r_WorkDay crs_WorkDay%rowtype;
    305 begin
    306     for   r_WorkDay in crs_WorkDay loop
    307     dbms_output.put_line(r_WorkDay.ENAME||'已经工作了'||r_WorkDay.SPANDYEARS||'年,零'||r_WorkDay.months||'月,零'||r_WorkDay.days||'');
    308     end loop;
    309 end;
    310   
    311 --12:输入部门编号,按照下列加薪比例执行(用CASE实现,创建一个emp1表,修改emp1表的数据),并将更新前后的数据输出出来
    312 --  deptno  raise(%)
    313 --  10      5%
    314 --  20      10%
    315 --  30      15%
    316 --  40      20%
    317 --  加薪比例以现有的sal为标准
    318 --CASE expr WHEN comparison_expr THEN return_expr
    319 --[, WHEN comparison_expr THEN return_expr]... [ELSE else_expr] END
    320 declare
    321      cursor
    322          crs_caseTest
    323           is
    324           select * from emp1 for update of SAL;
    325           r_caseTest crs_caseTest%rowtype;
    326           salInfo emp1.sal%type;
    327      begin
    328          for r_caseTest in crs_caseTest loop
    329          case 
    330            when r_caseTest.DEPNO=10
    331            THEN salInfo:=r_caseTest.SAL*1.05;
    332            when r_caseTest.DEPNO=20
    333            THEN salInfo:=r_caseTest.SAL*1.1;
    334            when r_caseTest.DEPNO=30
    335            THEN salInfo:=r_caseTest.SAL*1.15;
    336             when r_caseTest.DEPNO=40
    337            THEN salInfo:=r_caseTest.SAL*1.2;
    338          end case;
    339           update emp1 set SAL=salInfo where current of crs_caseTest;
    340         end loop;
    341 end;
    342 
    343 --13:对每位员工的薪水进行判断,如果该员工薪水高于其所在部门的平均薪水,则将其薪水减50元,输出更新前后的薪水,员工姓名,所在部门编号。
    344 --AVG([distinct|all] expr) over (analytic_clause)
    345 ---作用:
    346 --按照analytic_clause中的规则求分组平均值。
    347   --分析函数语法:
    348   --FUNCTION_NAME(<argument>,<argument>...)
    349   --OVER
    350   --(<Partition-Clause><Order-by-Clause><Windowing Clause>)
    351      --PARTITION子句
    352      --按照表达式分区(就是分组),如果省略了分区子句,则全部的结果集被看作是一个单一的组
    353      select * from emp1
    354 DECLARE
    355      CURSOR 
    356      crs_testAvg
    357      IS
    358      select EMPNO,ENAME,JOB,SAL,DEPNO,AVG(SAL) OVER (PARTITION BY DEPNO ) AS DEP_AVG
    359      FROM EMP1 for update of SAL;
    360      r_testAvg crs_testAvg%rowtype;
    361      salInfo emp1.sal%type;
    362      begin
    363      for r_testAvg in crs_testAvg loop
    364      if r_testAvg.SAL>r_testAvg.DEP_AVG then
    365      salInfo:=r_testAvg.SAL-50;
    366      end if;
    367      update emp1 set SAL=salInfo where current of crs_testAvg;
    368      end loop;
    369 end;

    作者:Cboii

    本博客所有文章仅用于学习、研究和交流目的,欢迎非商业性质转载。

    由于博主的水平不高,不足和错误之处在所难免,希望大家能够批评指出。

    在wordpress安装、主题、插件以及开发上面有问题的,可以加入qq群:1140958614(Wp建站每日学习/交流群)进行学习和提问

    如果需要建站服务,可以直接联系我的qq:185369045

  • 相关阅读:
    ScrollView下嵌套GridView或ListView默认不在顶部的解决方法
    Hdu5303 Delicious Apples 贪心
    javax.xml.transform.TransformerConfigurationException: Could not compile stylesheet
    unable to execute dex: multiple dex files Cocos2dxAccelerometer
    Unity游戏小地图生成
    LeetCode Spiral Matrix II
    &lt;九度 OJ&gt;题目1012:畅通project
    cpu信息
    挖一挖不经常使用到而又非常有用的重载-Split
    hdu1501 Zipper--DFS
  • 原文地址:https://www.cnblogs.com/chenboyi081/p/4253618.html
Copyright © 2020-2023  润新知