ITPub博客

首页 > 数据库 > Oracle > Oracle 游标使用全解

Oracle 游标使用全解

Oracle 作者:studywell 时间:2014-11-13 22:04:14 0 删除 编辑
转自:http://www.cnblogs.com/sc-xx/archive/2011/12/03/2275084.html

整理的很好,收藏下来

点击(此处)折叠或打开

  1. -- 声明游标;CURSOR cursor_name IS select_statement

  2. --For 循环游标
  3. --(1)定义游标
  4. --(2)定义游标变量
  5. --(3)使用for循环来使用这个游标
  6. declare
  7.        --类型定义
  8.        cursor c_job
  9.        is
  10.        select empno,ename,job,sal
  11.        from emp
  12.        where job=\'MANAGER\';
  13.        --定义一个游标变量v_cinfo c_emp%ROWTYPE ,该类型为游标c_emp中的一行数据类型
  14.        c_row c_job%rowtype;
  15. begin
  16.        for c_row in c_job loop
  17.          dbms_output.put_line(c_row.empno||\'-\'||c_row.ename||\'-\'||c_row.job||\'-\'||c_row.sal);
  18.        end loop;
  19. end;


  20.       
  21. --Fetch游标
  22. --使用的时候必须要明确的打开和关闭

  23. declare
  24.        --类型定义
  25.        cursor c_job
  26.        is
  27.        select empno,ename,job,sal
  28.        from emp
  29.        where job=\'MANAGER\';
  30.        --定义一个游标变量
  31.        c_row c_job%rowtype;
  32. begin
  33.        open c_job;
  34.          loop
  35.            --提取一行数据到c_row
  36.            fetch c_job into c_row;
  37.            --判读是否提取到值,没取到值就退出
  38.            --取到值c_job%notfound 是false
  39.            --取不到值c_job%notfound 是true
  40.            exit when c_job%notfound;
  41.             dbms_output.put_line(c_row.empno||\'-\'||c_row.ename||\'-\'||c_row.job||\'-\'||c_row.sal);
  42.          end loop;
  43.        --关闭游标
  44.       close c_job;
  45. end;

  46. --1:任意执行一个update操作,用隐式游标sql的属性%found,%notfound,%rowcount,%isopen观察update语句的执行情况。
  47.        begin
  48.          update emp set ENAME=\'ALEARK\' WHERE EMPNO=7469;
  49.          if sql%isopen then
  50.            dbms_output.put_line(\'Openging\');
  51.            else
  52.              dbms_output.put_line(\'closing\');
  53.              end if;
  54.           if sql%found then
  55.             dbms_output.put_line(\'游标指向了有效行\');--判断游标是否指向有效行
  56.             else
  57.               dbms_output.put_line(\'Sorry\');
  58.               end if;
  59.               if sql%notfound then
  60.                 dbms_output.put_line(\'Also Sorry\');
  61.                 else
  62.                   dbms_output.put_line(\'Haha\');
  63.                   end if;
  64.                    dbms_output.put_line(sql%rowcount);
  65.                    exception
  66.                      when no_data_found then
  67.                        dbms_output.put_line(\'Sorry No data\');
  68.                        when too_many_rows then
  69.                          dbms_output.put_line(\'Too Many rows\');
  70.                          end;
  71. declare
  72.        empNumber emp.EMPNO%TYPE;
  73.        empName emp.ENAME%TYPE;
  74.        begin
  75.          if sql%isopen then
  76.            dbms_output.put_line(\'Cursor is opinging\');
  77.            else
  78.              dbms_output.put_line(\'Cursor is Close\');
  79.              end if;
  80.              if sql%notfound then
  81.                dbms_output.put_line(\'No Value\');
  82.                else
  83.                  dbms_output.put_line(empNumber);
  84.                  end if;
  85.                  dbms_output.put_line(sql%rowcount);
  86.                  dbms_output.put_line(\'-------------\');
  87.                  
  88.                  select EMPNO,ENAME into empNumber,empName from emp where EMPNO=7499;
  89.                  dbms_output.put_line(sql%rowcount);
  90.                  
  91.                 if sql%isopen then
  92.                 dbms_output.put_line(\'Cursor is opinging\');
  93.                 else
  94.                 dbms_output.put_line(\'Cursor is Closing\');
  95.                 end if;
  96.                  if sql%notfound then
  97.                  dbms_output.put_line(\'No Value\');
  98.                  else
  99.                  dbms_output.put_line(empNumber);
  100.                  end if;
  101.                  exception
  102.                    when no_data_found then
  103.                      dbms_output.put_line(\'No Value\');
  104.                      when too_many_rows then
  105.                        dbms_output.put_line(\'too many rows\');
  106.                        end;
  107.                    
  108.                  
  109.        
  110. --2,使用游标和loop循环来显示所有部门的名称
  111. --游标声明
  112. declare
  113.        cursor csr_dept
  114.        is
  115.        --select语句
  116.        select DNAME
  117.        from Depth;
  118.        --指定行指针,这句话应该是指定和csr_dept行类型相同的变量
  119.        row_dept csr_dept%rowtype;
  120. begin
  121.        --for循环
  122.        for row_dept in csr_dept loop
  123.            dbms_output.put_line(\'部门名称:\'||row_dept.DNAME);
  124.        end loop;
  125. end;


  126. --3,使用游标和while循环来显示所有部门的的地理位置(用%found属性)
  127. declare
  128.        --游标声明
  129.        cursor csr_TestWhile
  130.        is
  131.        --select语句
  132.        select LOC
  133.        from Depth;
  134.        --指定行指针
  135.        row_loc csr_TestWhile%rowtype;
  136. begin
  137.   --打开游标
  138.        open csr_TestWhile;
  139.        --给第一行喂数据
  140.        fetch csr_TestWhile into row_loc;
  141.        --测试是否有数据,并执行循环
  142.          while csr_TestWhile%found loop
  143.            dbms_output.put_line(\'部门地点:\'||row_loc.LOC);
  144.            --给下一行喂数据
  145.            fetch csr_TestWhile into row_loc;
  146.          end loop;
  147.        close csr_TestWhile;
  148. end;
  149. select * from emp



  150.        
  151. --4,接收用户输入的部门编号,用for循环和游标,打印出此部门的所有雇员的所有信息(使用循环游标)
  152. --CURSOR cursor_name[(parameter[,parameter],...)] IS select_statement;
  153. --定义参数的语法如下:Parameter_name [IN] data_type[{:=|DEFAULT} value]

  154. declare
  155.       CURSOR
  156.       c_dept(p_deptNo number)
  157.       is
  158.       select * from emp where emp.depno=p_deptNo;
  159.       r_emp emp%rowtype;
  160. begin
  161.         for r_emp in c_dept(20) loop
  162.             dbms_output.put_line(\'员工号:\'||r_emp.EMPNO||\'员工名:\'||r_emp.ENAME||\'工资:\'||r_emp.SAL);
  163.         end loop;
  164. end;
  165. select * from emp
  166. --5:向游标传递一个工种,显示此工种的所有雇员的所有信息(使用参数游标)
  167. declare
  168.        cursor
  169.        c_job(p_job nvarchar2)
  170.        is
  171.        select * from emp where JOB=p_job;
  172.        r_job emp%rowtype;
  173. begin
  174.        for r_job in c_job(\'CLERK\') loop
  175.            dbms_output.put_line(\'员工号\'||r_job.EMPNO||\' \'||\'员工姓名\'||r_job.ENAME);
  176.         end loop;
  177. end;
  178. SELECT * FROM EMP

  179. --6:用更新游标来为雇员加佣金:(用if实现,创建一个与emp表一摸一样的emp1表,对emp1表进行修改操作),并将更新前后的数据输出出来
  180. --http://zheng12tian.iteye.com/blog/815770
  181.         create table emp1 as select * from emp;
  182.         
  183. declare
  184.         cursor
  185.         csr_Update
  186.         is
  187.         select * from emp1 for update OF SAL;
  188.         empInfo csr_Update%rowtype;
  189.         saleInfo emp1.SAL%TYPE;
  190. begin
  191.     FOR empInfo IN csr_Update LOOP
  192.       IF empInfo.SAL<1500 THEN
  193.         saleInfo:=empInfo.SAL*1.2;
  194.        elsif empInfo.SAL<2000 THEN
  195.         saleInfo:=empInfo.SAL*1.5;
  196.         elsif empInfo.SAL<3000 THEN
  197.         saleInfo:=empInfo.SAL*2;
  198.       END IF;
  199.       UPDATE emp1 SET SAL=saleInfo WHERE CURRENT OF csr_Update;
  200.      END LOOP;
  201. END;

  202. --7:编写一个PL/SQL程序块,对名字以‘A’或‘S’开始的所有雇员按他们的基本薪水(sal)的10%给他们加薪(对emp1表进行修改操作)
  203. declare
  204.      cursor
  205.       csr_AddSal
  206.      is
  207.       select * from emp1 where ENAME LIKE \'A%\' OR ENAME LIKE \'S%\' for update OF SAL;
  208.       r_AddSal csr_AddSal%rowtype;
  209.       saleInfo emp1.SAL%TYPE;
  210. begin
  211.       for r_AddSal in csr_AddSal loop
  212.           dbms_output.put_line(r_AddSal.ENAME||\'原来的工资:\'||r_AddSal.SAL);
  213.           saleInfo:=r_AddSal.SAL*1.1;
  214.           UPDATE emp1 SET SAL=saleInfo WHERE CURRENT OF csr_AddSal;
  215.       end loop;
  216. end;
  217. --8:编写一个PL/SQL程序块,对所有的salesman增加佣金(comm)500
  218. declare
  219.       cursor
  220.           csr_AddComm(p_job nvarchar2)
  221.       is
  222.           select * from emp1 where JOB=p_job FOR UPDATE OF COMM;
  223.       r_AddComm emp1%rowtype;
  224.       commInfo emp1.comm%type;
  225. begin
  226.     for r_AddComm in csr_AddComm(\'SALESMAN\') LOOP
  227.         commInfo:=r_AddComm.COMM+500;
  228.          UPDATE EMP1 SET COMM=commInfo where CURRENT OF csr_AddComm;
  229.     END LOOP;
  230. END;

  231. --9:编写一个PL/SQL程序块,以提升2个资格最老的职员为MANAGER(工作时间越长,资格越老)
  232. --(提示:可以定义一个变量作为计数器控制游标只提取两条数据;也可以在声明游标的时候把雇员中资格最老的两个人查出来放到游标中。)
  233. declare
  234.     cursor crs_testComput
  235.     is
  236.     select * from emp1 order by HIREDATE asc;
  237.     --计数器
  238.     top_two number:=2;
  239.     r_testComput crs_testComput%rowtype;
  240. begin
  241.     open crs_testComput;
  242.        FETCH crs_testComput INTO r_testComput;
  243.           while top_two>0 loop
  244.              dbms_output.put_line(\'员工姓名:\'||r_testComput.ENAME||\' 工作时间:\'||r_testComput.HIREDATE);
  245.              --计速器减一
  246.              top_two:=top_two-1;
  247.              FETCH crs_testComput INTO r_testComput;
  248.            end loop;
  249.      close crs_testComput;
  250. end;
  251.     

  252. --10:编写一个PL/SQL程序块,对所有雇员按他们的基本薪水(sal)的20%为他们加薪,
  253. --如果增加的薪水大于300就取消加薪(对emp1表进行修改操作,并将更新前后的数据输出出来)
  254. declare
  255.     cursor
  256.         crs_UpadateSal
  257.     is
  258.         select * from emp1 for update of SAL;
  259.         r_UpdateSal crs_UpadateSal%rowtype;
  260.         salAdd emp1.sal%type;
  261.         salInfo emp1.sal%type;
  262. begin
  263.         for r_UpdateSal in crs_UpadateSal loop
  264.            salAdd:= r_UpdateSal.SAL*0.2;
  265.            if salAdd>300 then
  266.              salInfo:=r_UpdateSal.SAL;
  267.               dbms_output.put_line(r_UpdateSal.ENAME||\': 加薪失败。\'||\'薪水维持在:\'||r_UpdateSal.SAL);
  268.              else
  269.               salInfo:=r_UpdateSal.SAL+salAdd;
  270.               dbms_output.put_line(r_UpdateSal.ENAME||\': 加薪成功.\'||\'薪水变为:\'||salInfo);
  271.            end if;
  272.            update emp1 set SAL=salInfo where current of crs_UpadateSal;
  273.         end loop;
  274. end;
  275.      
  276. --11:将每位员工工作了多少年零多少月零多少天输出出来
  277. --近似
  278.   --CEIL(n)函数:取大于等于数值n的最小整数
  279.   --FLOOR(n)函数:取小于等于数值n的最大整数
  280.   --truc的用法 http://publish.it168.com/2005/1028/20051028034101.shtml
  281. declare
  282.   cursor
  283.    crs_WorkDay
  284.    is
  285.    select ENAME,HIREDATE, trunc(months_between(sysdate, hiredate) / 12) AS SPANDYEARS,
  286.        trunc(mod(months_between(sysdate, hiredate), 12)) AS months,
  287.        trunc(mod(mod(sysdate - hiredate, 365), 12)) as days
  288.    from emp1;
  289.   r_WorkDay crs_WorkDay%rowtype;
  290. begin
  291.     for r_WorkDay in crs_WorkDay loop
  292.     dbms_output.put_line(r_WorkDay.ENAME||\'已经工作了\'||r_WorkDay.SPANDYEARS||\'年,零\'||r_WorkDay.months||\'月,零\'||r_WorkDay.days||\'天\');
  293.     end loop;
  294. end;
  295.   
  296. --12:输入部门编号,按照下列加薪比例执行(用CASE实现,创建一个emp1表,修改emp1表的数据),并将更新前后的数据输出出来
  297. -- deptno raise(%)
  298. -- 10 5%
  299. -- 20 10%
  300. -- 30 15%
  301. -- 40 20%
  302. -- 加薪比例以现有的sal为标准
  303. --CASE expr WHEN comparison_expr THEN return_expr
  304. --[, WHEN comparison_expr THEN return_expr]... [ELSE else_expr] END
  305. declare
  306.      cursor
  307.          crs_caseTest
  308.           is
  309.           select * from emp1 for update of SAL;
  310.           r_caseTest crs_caseTest%rowtype;
  311.           salInfo emp1.sal%type;
  312.      begin
  313.          for r_caseTest in crs_caseTest loop
  314.          case
  315.            when r_caseTest.DEPNO=10
  316.            THEN salInfo:=r_caseTest.SAL*1.05;
  317.            when r_caseTest.DEPNO=20
  318.            THEN salInfo:=r_caseTest.SAL*1.1;
  319.            when r_caseTest.DEPNO=30
  320.            THEN salInfo:=r_caseTest.SAL*1.15;
  321.             when r_caseTest.DEPNO=40
  322.            THEN salInfo:=r_caseTest.SAL*1.2;
  323.          end case;
  324.           update emp1 set SAL=salInfo where current of crs_caseTest;
  325.         end loop;
  326. end;

  327. --13:对每位员工的薪水进行判断,如果该员工薪水高于其所在部门的平均薪水,则将其薪水减50元,输出更新前后的薪水,员工姓名,所在部门编号。
  328. --AVG([distinct|all] expr) over (analytic_clause)
  329. ---作用:
  330. --按照analytic_clause中的规则求分组平均值。
  331.   --分析函数语法:
  332.   --FUNCTION_NAME(,...)
  333.   --OVER
  334.   --()
  335.      --PARTITION子句
  336.      --按照表达式分区(就是分组),如果省略了分区子句,则全部的结果集被看作是一个单一的组
  337.      select * from emp1
  338. DECLARE
  339.      CURSOR
  340.      crs_testAvg
  341.      IS
  342.      select EMPNO,ENAME,JOB,SAL,DEPNO,AVG(SAL) OVER (PARTITION BY DEPNO ) AS DEP_AVG
  343.      FROM EMP1 for update of SAL;
  344.      r_testAvg crs_testAvg%rowtype;
  345.      salInfo emp1.sal%type;
  346.      begin
  347.      for r_testAvg in crs_testAvg loop
  348.      if r_testAvg.SAL>r_testAvg.DEP_AVG then
  349.      salInfo:=r_testAvg.SAL-50;
  350.      end if;
  351.      update emp1 set SAL=salInfo where current of crs_testAvg;
  352.      end loop;
  353. end;

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





来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/29519108/viewspace-1331846/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2014-03-04

  • 博文量
    307
  • 访问量
    535350