Oracle 遊標使用全解

studywell發表於2014-11-13
轉自: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部落格 ” ,連結:http://blog.itpub.net/29519108/viewspace-1331846/,如需轉載,請註明出處,否則將追究法律責任。

相關文章