乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      游標(biāo)

       修行的嘟嘟 2011-08-03

      還是看下上篇的那段代碼:

      create proc pro_abc
      as
      declare @p1 nvarchar(50),@p2 int;
      declare my_cursor cursor scroll dynamic
      for SELECT F_CR_JSGM,f_nb_xmbm FROM B_JIHUA_XIANGMU WHERE NOT  F_CR_JSGM IS NULL
      open my_cursor
      fetch next from my_cursor into @p1,@p2
      while(@@fetch_status=0)
      begin
      update b_jihua_jsgm set f_cr_jsgm2=@p1 where f_nb_xmbm=@p2
      fetch next from my_cursor into @p1,@p2
      end
      close my_cursor
      deallocate my_cursor
      
      分解:這段是存儲過程
      create proc pro_abc--
      as
      declare @p1 nvarchar(50),@p2 int;
      begin
      select 'aaaa'
      end
      

      加上游標(biāo)就是這樣了

      create proc pro_abc
      as
      declare @p1 nvarchar(50),@p2 int;--聲明變量和類型
      --聲明游標(biāo)的名稱my_cursor;這個游標(biāo)所用到的SQL語句
      ----scroll表示可隨意移動游標(biāo)指        針(否則只能向前),dynamic表示可以讀寫游標(biāo)(否則游標(biāo)只讀)*/
      declare my_cursor cursor scroll dynamic
      for SELECT F_CR_JSGM,f_nb_xmbm FROM B_JIHUA_XIANGMU WHERE NOT  F_CR_JSGM IS NULL
      --打開游標(biāo)
      open my_cursor
      --必須用FETCH語句來取得數(shù)據(jù) 可以傳遞參數(shù)
      fetch next from my_cursor into @p1,@p2
      --fetch_status=0一切正常
      while(@@fetch_status=0)
      begin
      update b_jihua_jsgm set f_cr_jsgm2=@p1 where f_nb_xmbm=@p2
      fetch next from my_cursor into @p1,@p2
      end
      --關(guān)閉游標(biāo)
      close my_cursor
      --刪除游標(biāo)資源
      deallocate my_cursor
      

      XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

      聲明游標(biāo) 
      象使用其它類型的變量一樣,使用一個游標(biāo)之前,首先應(yīng)當(dāng)聲明它。游標(biāo)的聲明包括兩個部分:游標(biāo)的名稱;這個游標(biāo)所用到的SQL語句

      在游標(biāo)的聲明中有一點(diǎn)值得注意的是,如同其它變量的聲明一樣,聲明游標(biāo)的這一段代碼行是不執(zhí)行的,您不能將debug時的斷點(diǎn)設(shè)在這一代碼行上,也不能用IF...END IF語句來聲明兩個同名的游標(biāo),如下列的代碼就是錯誤的。 
      IF Is_prov="北京"THEN 
      DECLARE CustomerCursor CURSOR FOR 
      SELECT acct_no,name,balance 
      FROM customer 
      WHERE province="北京"; 
      ELSE 
      DECLARE CustomerCursor CURSOR FOR 
      SELECT acct_no,name,balance 
      FROM customer 
      WHERE province〈〉"北京"; 
      END IF 

      ----------------------------------

      由于打開游標(biāo)是對數(shù)據(jù)庫進(jìn)行一些SQL SELECT的操作,它將耗費(fèi)一段時間,主要取決于您使用的系統(tǒng)性能和這條語句的復(fù)雜程度。如果執(zhí)行的時間較長,可以考慮將屏幕上顯示的鼠標(biāo)改為hourglass(這句不會)

      -------------------------------------

      提取數(shù)據(jù) 
      當(dāng)用OPEN語句打開了游標(biāo)并在數(shù)據(jù)庫中執(zhí)行了查詢后,您不能立即利用在查詢結(jié)果集中的數(shù)據(jù)。您必須用FETCH語句來取得數(shù)據(jù)。一條FETCH語句一次可以將一條記錄放入程序員指定的變量中。事實(shí)上,FETCH語句是游標(biāo)使用的核心。在DataWindow和DataStore中,執(zhí)行了Retrieve()函數(shù)以后,查詢的所有結(jié)果全部可以得到;而使用游標(biāo),我們只能逐條記錄地得到查詢結(jié)果。 
      已經(jīng)聲明并打開一個游標(biāo)后,我們就可以將數(shù)據(jù)放入任意的變量中。在FETCH語句中您可以指定游標(biāo)的名稱和目標(biāo)變量的名稱

      從語法上講,上面所述的就是一條合法的取數(shù)據(jù)的語句,但是一般我們使用游標(biāo)卻還應(yīng)當(dāng)包括其它的部分。正如我們前面所談到的,游標(biāo)只能一次從后臺數(shù)據(jù)庫中取一條記錄,而在多數(shù)情況下,我們所想要作的是在數(shù)據(jù)庫中從第一條記錄開始提取,一直到結(jié)束。所以我們一般要將游標(biāo)提取數(shù)據(jù)的語句放在一個循環(huán)體內(nèi),直至將結(jié)果集中的全部數(shù)據(jù)提取后,跳出循環(huán)圈。通過檢測SQLCA.SQL-CODE的值,可以得知最后一條FETCH語句是否成功。一般,當(dāng)SQLCODE值為0時表明一切正常,100表示已經(jīng)取到了結(jié)果集的末尾,而其它值均表明操作出了問題,

      更多的就是這里了http://www./344071.html

      今天就學(xué)到這里 再見
       
       

      顯示游標(biāo)

      顯示游標(biāo)包括四種屬性:

      %ISOPEN :檢測游標(biāo)是否已經(jīng)打開

      %FOUND :檢測游標(biāo)結(jié)果集是否存在數(shù)據(jù),存在則返回TRUE

      %NOTFOUND :檢測游標(biāo)結(jié)果集是否不存在數(shù)據(jù),不存在則返回TRUE

      %ROWCOUNT :返回已提取的實(shí)際行數(shù)

      使用顯示游標(biāo)

      定義游標(biāo):CURSOR cursor_name IS select_statement;

      打開游標(biāo):OPEN cursor_name;

      提取數(shù)據(jù):FETCH cursor_name INTO variable1[,variable2,…];

      FETCH INTO每次只能提取一行數(shù)據(jù),批量數(shù)據(jù)需使用循環(huán)

      使用游標(biāo)變量接受數(shù)據(jù):

      SQL> declare

      2 cursor emp_cursor is

      3 select ename,job,sal from emp where deptno=&dno;

      4 vname emp.ename%type;

      5 vsal emp.sal%type;

      6 vjob emp.job%type;

      7 begin Oracle 學(xué)習(xí)筆記 第 74 頁 共 90 頁

      8 open emp_cursor;

      9 loop

      10 fetch emp_cursor into vname,vjob,vsal;

      11 exit when emp_cursor%notfound;

      12 dbms_output.put_line('姓名:'||vname||',崗位:'||vjob||',工資:'||vsal);

      13 end loop;

      14 close emp_cursor;

      15 end;

      16 /

      輸入 dno 的值: 30

      姓名:ALLEN,崗位:SALESMAN,工資:1600

      姓名:WARD,崗位:SALESMAN,工資:1250

      姓名:JONES,崗位:MANAGER,工資:3272.5

      PL/SQL 過程已成功完成。

      使用PL/SQL記錄變量接受游標(biāo)數(shù)據(jù):簡化單行數(shù)據(jù)處理

      SQL> declare

      2 cursor ecur is select ename,sal from emp order by sal desc;

      3 erec ecur%rowtype;

      4 begin

      5 open ecur;

      6 loop

      7 fetch ecur into erec;

      8 exit when ecur%notfound or ecur%rowcount>&n;

      9 dbms_output.put_line('姓名:'||erec.ename||',工資:'||erec.sal);

      10 end loop;

      11 close ecur;

      12 end;

      13 /

      輸入 n 的值: 5

      姓名:KING,工資:5000

      姓名:FORD,工資:3300

      姓名:JONES,工資:3272.5

      姓名:BLAKE,工資:2850

      姓名:MARY,工資:2000

      PL/SQL 過程已成功完成。

      使用PL/SQL集合變量接受游標(biāo)數(shù)據(jù):簡化多行多列數(shù)據(jù)處理

      SQL> declare

      2 cursor ec is select ename,sal from emp where lower(job)=lower('&job');

      3 type etype is table of ec%rowtype index by binary_integer;

      4 et etype;

      5 i int;

      6 begin

      7 open ec;

      8 loop Oracle 學(xué)習(xí)筆記 第 75 頁 共 90 頁

      9 i:=ec%rowcount+1;

      10 fetch ec into et(i);

      11 exit when ec%notfound;

      12 dbms_output.put_line('姓名:'||et(i).ename||',工資:'||et(i).sal);

      13 end loop;

      14 close ec;

      15 end;

      16 /

      輸入 job 的值: manager

      姓名:JONES,工資:3272.5

      姓名:BLAKE,工資:2850

      姓名:CLARK,工資:1500

      PL/SQL 過程已成功完成。

      游標(biāo)FOR循環(huán)

      使用游標(biāo)for循環(huán)時,oracle會隱含的打開游標(biāo),提取數(shù)據(jù)并關(guān)閉游標(biāo)

      在游標(biāo)for循環(huán)中引用已定義游標(biāo):

      SQL> declare

      2 cursor ec is select ename,hiredate from emp order by hiredate desc;

      3 begin

      4 for erec in ec loop

      5 dbms_output.put_line('姓名:'||erec.ename||',工作日期:'||erec.hiredate);

      6 exit when ec%rowcount=&n;

      7 end loop;

      8 end;

      9 /

      輸入 n 的值: 3

      姓名:MARY,工作日期:

      姓名:ADAMS,工作日期:23-5月 -87

      姓名:SCOTT,工作日期:01-1月 -84

      PL/SQL 過程已成功完成。

      在游標(biāo)for循環(huán)中直接引用子查詢:

      SQL> begin

      2 for erec in (select ename,hiredate,rownum from emp order by hiredate) loop

      3 dbms_output.put_line('姓名:'||erec.ename||',工作日期:'||erec.hiredate);

      4 exit when erec.rownum=&n;end loop;

      5 end;

      6 /

      輸入 n 的值: 2

      姓名:ALLEN,工作日期:20-2月 -81

      姓名:WARD,工作日期:22-2月 -81

      PL/SQL 過程已成功完成。

      參數(shù)游標(biāo):參數(shù)只能指定數(shù)據(jù)類型,不能指定長度,而且必須在where子句中引用參數(shù)

      SQL> declare Oracle 學(xué)習(xí)筆記 第 76 頁 共 90 頁

      2 cursor ec(dno number) is select ename,job from emp where deptno=dno;

      3 begin

      4 for erec in ec(&dno) loop

      5 dbms_output.put_line('姓名:'||erec.ename||',崗位:'||erec.job);

      6 end loop;

      7 end;

      8 /

      輸入 dno 的值: 30

      姓名:ALLEN,崗位:SALESMAN

      姓名:WARD,崗位:SALESMAN

      姓名:JONES,崗位:MANAGER

      PL/SQL 過程已成功完成。

      更新游標(biāo)行

      declare

      cursor emp_cursor is select ename,sal,deptno from emp for update;

      dno int:=&no;

      begin

      for emp_record in emp_cursor loop

      if emp_record.deptno=dno then

      dbms_output.put_line(‘姓名:’||emp_record.ename||’,原工資:’||emp_record.sal);

      update emp set sal=sal*1.1 where current of emp_cursor;

      end if;

      end loop;

      end;

      /

      刪除游標(biāo)行

      declare

      cursor emp_cursor is select ename from emp for update;

      name varchar2(10):=lower(‘&name’);

      begin

      for emp_record in emp_cursor loop

      if lower(emp_record.ename)=name then

      delete from emp where current of emp_cursor;

      else

      dbms_output.put_line(‘姓名:’||emp_record.ename);

      end if;

      end loop;

      end;

      /

      使用for子句在特定表上加共享鎖(涉及多張表時的同步問題)

      SQL> declare

      2 cursor emp_cursor is Oracle 學(xué)習(xí)筆記第 77 頁 共 90 頁

      select a.dname,b.ename from dept a JOIN emp b ON a.deprno=b.deptno;

      3 name varchar2(10):=lower('&name');

      4 begin

      5 for emp_record in emp_cursor loop

      6 if lower(emp_record.dname)=name then

      7 dbms_output.put_line(‘姓名:’||emp_record.ename);

      8 delete from emp where current of emp_cursor;

      9 end if;

      10 end loop;

      11 end;

      12 /

      輸入 name 的值: sales

      PL/SQL過程已完成。

      游標(biāo)變量

      游標(biāo)變量是基于REF CURSOR類型所定義的變量,它實(shí)際上是指向內(nèi)存地址的指針。使用顯式游標(biāo)只能定義靜態(tài)游標(biāo),而通過使用游標(biāo)變量可以在打開游標(biāo)時指定其對應(yīng)的select語句,從而實(shí)現(xiàn)動態(tài)游標(biāo)。

      使用無返回類型的游標(biāo)變量

      SQL> set serveroutput on

      SQL> set verify off

      SQL> declare

      2 type ref_cursor_type is ref cursor;

      3 rc ref_cursor_type;

      4 v1 number(6);

      5 v2 varchar2(10);

      6 begin

      7 open rc for

      8 select &col1 col1,&col2 col2 from &table where &cond;

      9 loop

      10 fetch rc into v1,v2;

      11 exit when rc%notfound;

      12 dbms_output.put_line('col1= '||v1||',col2= '||v2);

      13 end loop;

      14 close rc;

      15 end;

      16 /

      輸入 col1 的值: empno

      輸入 col2 的值: ename

      輸入 table 的值: emp

      輸入 cond 的值: deptno=10

      col1= 7782,col2= CLARK

      col1= 7839,col2= KING

      col1= 7934,col2= MILLER

      PL/SQL 過程已成功完成。 Oracle 學(xué)習(xí)筆記 第 78 頁 共 90 頁

      使用有返回類型的游標(biāo)變量

      SQL> declare

      2 type emp_cursor_type is ref cursor return emp%rowtype;

      3 ec emp_cursor_type;

      4 er emp%rowtype;

      5 begin

      6 open ec for select * from emp where deptno=&dno;

      7 loop

      8 fetch ec into er;

      9 exit when ec%notfound;

      10 dbms_output.put_line('姓名:'||er.ename||',工資:'||er.sal);

      11 end loop;

      12 close ec;

      13 end;

      14 /

      輸入 dno 的值: 20

      姓名:SMITH,工資:800

      姓名:JONES,工資:2975

      姓名:SCOTT,工資:3000

      姓名:ADAMS,工資:1100

      姓名:FORD,工資:3000

      PL/SQL 過程已成功完成。

      使用批量提取

      使用fetch…bulk collect提取所有數(shù)據(jù);

      SQL> declare

      2 cursor ec is

      3 select * from emp where lower(job)=lower('&job');

      4 type etype is table of emp%rowtype;

      5 et etype;

      6 begin

      7 open ec;

      8 fetch ec bulk collect into et;

      9 close ec;

      10 for i in 1..et.count loop

      11 dbms_output.put_line('姓名:'||et(i).ename||',工資:'||et(i).sal);

      12 end loop;

      13 end;

      14 /

      輸入 job 的值: clerk

      姓名:SMITH,工資:800

      姓名:ADAMS,工資:1100

      姓名:JAMES,工資:950

      姓名:MILLER,工資:1300

      PL/SQL 過程已成功完成。 Oracle 學(xué)習(xí)筆記 第 79 頁 共 90 頁

      使用LIMIT子句限制提取行數(shù)

      SQL> declare

      2 cursor ec is select * from emp;

      3 type emp_array_type is varray(5) of emp%rowtype;

      4 ea emp_array_type;

      5 begin

      6 open ec;

      7 loop

      8 fetch ec bulk collect into ea limit &rows;

      9 for i in 1..ea.count loop

      10 dbms_output.put_line('姓名:'||ea(i).ename||',工資:'||ea(i).sal);

      11 end loop;

      12 exit when ec%notfound;

      13 end loop;

      14 close ec;

      15 end;

      16 /

      輸入 rows 的值: 4

      姓名:SMITH,工資:800

      姓名:ALLEN,工資:1600

      姓名:WARD,工資:1250

      姓名:JONES,工資:2975

      姓名:MARTIN,工資:1250

      姓名:BLAKE,工資:2850

      姓名:CLARK,工資:2450

      姓名:SCOTT,工資:3000

      姓名:KING,工資:5000

      姓名:TURNER,工資:1500

      姓名:ADAMS,工資:1100

      姓名:JAMES,工資:950

      姓名:FORD,工資:3000

      姓名:MILLER,工資:1300

      PL/SQL 過程已成功完成。

      使用cursor表達(dá)式

      SQL> declare

      2 cursor dept_cursor(no number) is

      3 select a.dname,cursor(select * from emp where deptno=a.deptno)

      4 from dept a where a.deptno=no;

      5 type ref_cursor_type is ref cursor;

      6 ec ref_cursor_type;

      7 er emp%rowtype;

      8 vdname dept.dname%type;

      9 begin

      10 open dept_cursor(&dno); Oracle 學(xué)習(xí)筆記第 80 頁 共 90 頁

      11 loop

      12 fetch dept_cursor into vdname,ec;

      13 exit when dept_cursor%notfound;

      14 dbms_output.put_line('部門名:'||vdname);

      15 loop

      16 fetch ec into er;

      17 exit when ec%notfound;

      18 dbms_output.put_line('----雇員名:'||er.ename||',崗位:'||er.job);

      19 end loop;

      20 end loop;

      21 close dept_cursor;

      22 end;

      23 /

      輸入 dno 的值: 10

      部門名:ACCOUNTING

      ----雇員名:CLARK,崗位:MANAGER

      ----雇員名:KING,崗位:PRESIDENT

      ----雇員名:MILLER,崗位:CLERK

      PL/SQL 過程已成功完成。
       

      在存儲過程或觸發(fā)器中使用 Transact-SQL 游標(biāo)的典型過程為:

      1. 聲明 Transact-SQL 變量包含游標(biāo)返回的數(shù)據(jù)。為每個結(jié)果集列聲明一個變量。聲明足夠大的變量來保存列返回的值,并聲明變量的類型為可從列數(shù)據(jù)類型隱式轉(zhuǎn)換得到的數(shù)據(jù)類型。
      2. 使用 DECLARE CURSOR 語句將 Transact-SQL 游標(biāo)與 SELECT 語句相關(guān)聯(lián)。另外,DECLARE CURSOR 語句還定義游標(biāo)的特性,例如游標(biāo)名稱以及游標(biāo)是只讀還是只進(jìn)。
      3. 使用 OPEN 語句執(zhí)行 SELECT 語句并填充游標(biāo)。
      4. 使用 FETCH INTO 語句提取單個行,并將每列中的數(shù)據(jù)移至指定的變量中。然后,其他 Transact-SQL 語句可以引用那些變量來訪問提取的數(shù)據(jù)值。Transact-SQL 游標(biāo)不支持提取行塊。

      使用 CLOSE 語句結(jié)束游標(biāo)的使用。關(guān)閉游標(biāo)可以釋放某些資源,例如游標(biāo)結(jié)果集及其對當(dāng)前行的鎖定,但如果重新發(fā)出一個 OPEN 語句,則該游標(biāo)結(jié)構(gòu)仍可用于處理。由于游標(biāo)仍然存在,此時還不能重新使用該游標(biāo)的名稱。DEALLOCATE 語句則完全釋放分配給游標(biāo)的資源,包括游標(biāo)名稱。釋放游標(biāo)后,必須使用 DECLARE 語句來重新生成游標(biāo)。

      -----------------------------------------------------
      /*
       Use DECLARE @local_variable, DECLARE CURSOR and SET. */
      USE AdventureWorks
      GO


      DECLARE @MyVariable CURSOR

      DECLARE MyCursor CURSOR FOR
      SELECT LastName FROM AdventureWorks.Person.Contact

      SET @MyVariable =
       MyCursor
      GO

      /* Use DECLARE @local_variable and SET */
      DECLARE @MyVariable CURSOR

      SET @MyVariable = CURSOR SCROLL KEYSET FOR
      SELECT LastName FROM AdventureWorks.Person.Contact;
      DEALLOCATE
       MyCursor;
      -----------------------------------------------------

      USE AdventureWorks
      GO

      -- Declare the variables to store the values returned by FETCH.
      DECLARE @LastName varchar(50), @FirstName varchar(50)

      DECLARE contact_cursor CURSOR FOR

      SELECT LastName, FirstName FROM Person.Contact
      WHERE LastName LIKE 'B%'

      ORDER BY LastName, FirstName

      OPEN
       contact_cursor

      -- Perform the first fetch and store the values in variables.

      --
       Note: The variables are in the same order as the columns
      --
       in the SELECT statement. 

      FETCH NEXT FROM contact_cursor
      INTO @LastName@FirstName


      -- Check @@FETCH_STATUS to see if there are any more rows to fetch.
      WHILE @@FETCH_STATUS = 0
      BEGIN

         
      -- Concatenate and display the current values in the variables.
         PRINT 'Contact Name: ' + @FirstName + ' ' +  @LastName

         
      -- This is executed as long as the previous fetch succeeds.
         FETCH NEXT FROM contact_cursor
         
      INTO @LastName@FirstName

      END

      CLOSE contact_cursor
      DEALLOCATE
       contact_cursor
      GO

       

      一個游標(biāo)(cursor)可以被看作指向結(jié)果集(a set of rows)中一行的指針(pointer)。游標(biāo)每個時間點(diǎn)只能指向一行,但是可以根據(jù)需要指向結(jié)果集中其他的行。
      例如:SELECT * FROM employees WHERE sex='M'會返回所有性別為男的雇員,在初始的時候,游標(biāo)被放置在結(jié)果集中第一行的前面。使游標(biāo)指向第一行,要執(zhí)行FETCH。當(dāng)游標(biāo)指向結(jié)果集中一行的時候,可以對這行數(shù)據(jù)進(jìn)行加工處理,要想得到下一行數(shù)據(jù),要繼續(xù)執(zhí)行FETCH。FETCH操作可以重復(fù)執(zhí)行,直到完成結(jié)果集中的所有行
       
          在存儲過程中使用游標(biāo),有如下幾個步驟:
            聲明游標(biāo)、打開游標(biāo)、根據(jù)需要一次一行,講游標(biāo)指向的數(shù)據(jù)取到本地變量(local variables)中、結(jié)束時關(guān)閉游標(biāo)
         
         聲明游標(biāo):
          >>-DECLARE--cursor-name--CURSOR----+------------+--------->
                                                                '-WITH HOLD--'
          >-----+--------------------------------+--------------------->
                   |                       .-TO CALLER--.  |
                    '-WITH RETURN--+------------+--'
                                            '-TO CLIENT--'
          >----FOR--+-select-statement-+----------------------------><
                          '-statement-name---'    
        WITH RETURN子句用于將游標(biāo)所定義的結(jié)果集傳遞給另一個存儲過程或者應(yīng)用(an application)
        如果select語句中包含CURRENT DATE, CURRENT TIME和CURRENT TIMESTAMP,所有的FETCH語句都會返回相同的日期、時間、時間戳值,因?yàn)檫@些特定寄存器是在打開游標(biāo)(OPEN CURSOR)的時候進(jìn)行檢查的
         
          FETCH語法:
          >>-FETCH--+-------+---cursor-name---------->
                           '-FROM--'
                              .-,----------------.
                              V                        |
          >------INTO-----host-variable---+----------><
          FETCH語句使游標(biāo)指向結(jié)果集中的下一行,并且將游標(biāo)現(xiàn)在的位置賦值給特定的過程變量
      例如:一個公司,按照如下規(guī)則計算加薪金額:
       1.公司中除了總裁(president)外,所有人都會至少增加p_min的薪水
       2.任何獎金(bonus)高于$600的員工都會另增加4%
       3.員工的傭金(commission)越高,增加越少。傭金(commission)少于$2000的另增加3%,傭金(commission)在$2000到$3000的增加另2%
       4.傭金(commission)高于$3000的另增加1%
       5.無論每個員工增加多少,增加比例不能高于p_max
      CREATE PROCEDURE total_raise ( IN  p_min DEC(4,2)
                                                 , IN  p_max DEC(4,2)
                                                 , OUT p_total DEC(9,2) )
          LANGUAGE SQL
          SPECIFIC total_raise     
      tr: BEGIN
          -- Declare variables
          DECLARE v_salary DEC(9,2);
          DECLARE v_bonus  DEC(9,2);
          DECLARE v_comm   DEC(9,2);
          DECLARE v_raise  DEC(4,2);
          DECLARE v_job    VARCHAR(15) DEFAULT 'PRES';
          -- Declare returncode
          DECLARE SQLSTATE CHAR(5);

          -- Procedure logic
          DECLARE c_emp CURSOR FOR
              SELECT salary, bonus, comm
              FROM   employee
              WHERE  job != v_job;                              -- (1)這里的SELECT定義了結(jié)果集中的行和
                                                                                列
              OPEN c_emp;                                        -- (2)
       
              SET p_total = 0;
              FETCH FROM c_emp INTO v_salary, v_bonus, v_comm;  -- (3)得到一行數(shù)據(jù),并將其
                                                                                                 復(fù)制給本地變量
       
              WHILE ( SQLSTATE = '00000' ) DO                   --SQLSTATE 00000: 操作執(zhí)行成功,
                                                                                  并且未產(chǎn)生任何類型的警告或異常情
                                                                                  況。通過這個可以檢查是否到達(dá)最后一行
                 SET v_raise = p_min;
                 IF ( v_bonus >= 600 ) THEN
                     SET v_raise = v_raise + 0.04;
                 END IF;

                 IF ( v_comm < 2000 ) THEN
                     SET v_raise = v_raise + 0.03;
                 ELSEIF ( v_comm < 3000 ) THEN
                     SET v_raise = v_raise + 0.02;
                 ELSE
                     SET v_raise = v_raise + 0.01;
                 END IF;

                 IF ( v_raise > p_max ) THEN
                     SET v_raise = p_max;
                 END IF;

                 SET p_total = p_total + v_salary * v_raise;
                 FETCH FROM c_emp INTO v_salary, v_bonus, v_comm;  -- (4)在WHILE邏輯中得到
                                                                                                    更多的行數(shù)據(jù)
             END WHILE;

             CLOSE c_emp;                                          -- (5)
         END tr
          如果只是想把結(jié)果集中的第一個值復(fù)制給本地變量,而聲明一個游標(biāo)是不恰當(dāng)?shù)?,因?yàn)榇蜷_游標(biāo)會耗費(fèi)很多資源。所以如下這段代碼:
      DECLARE c_tmp CURSOR FOR
              SELECT c1
              FROM t1;
      OPEN c_emp;
      FETCH FROM c_emp INTO v_c1;
      CLOSE c_emp;
      應(yīng)當(dāng)用有FETCH FIRST 1 ROW ONLY的子句的SQL語句:SELECT c1 INTO v_c1 FROM t1 FETCH FIRST 1 ROW ONLY;
        
        positioned delete:利用游標(biāo)刪除當(dāng)前行 
        一個用于刪除的游標(biāo)(a deletable cursor)應(yīng)該符合以下的要求:
           1.每個outer fullselect中的FROM子句只跟一個表有關(guān)
           2.outer fullselect不包含VALUES, GROUP BY, 或者HAVING子句,并且不包括列函數(shù)
           3.outer fullselect的select列表中不包含DISTINCT
           4.select語句不包含ORDER BY或FOR READ ONLY子句
           5.游標(biāo)是靜態(tài)定義的,或者明確了FOR UPDATE子句
      >>-DELETE FROM-|----table-name---------|--------------->
                              +-----view-name---------+
      >----WHERE CURRENT OF--cursor-name--------------------><
      例如:在emp_act表中,如果記錄的時間比輸入?yún)?shù)p_date早的話,就將該記錄刪除,并返回刪除記錄總數(shù)
      CREATE PROCEDURE cleanup_act ( IN  p_date    DATE
                                                   , OUT p_deleted INT )
          LANGUAGE SQL
          SPECIFIC cleanup_act                         
      ca: BEGIN
          -- Declare variable
          DECLARE v_date DATE;
          -- Declare returncode
          DECLARE SQLSTATE CHAR(5);

          -- Procedure logic

          DECLARE c_emp CURSOR FOR                       -- (1)和上面那種read-only cursor語法
                                                                            類似,只是多了FOR UPDATE
              SELECT emendate
              FROM emp_act
          FOR UPDATE;

          OPEN c_emp;

          FETCH FROM c_emp INTO v_date;                 --注意此處,不要落了
          SET p_deleted = 0;

          WHILE ( SQLSTATE = '00000' ) DO
              IF ( v_date < p_date ) THEN
                  DELETE FROM emp_act
                  WHERE CURRENT OF c_emp;                -- (2)
                  SET p_deleted = p_deleted + 1;
              END IF;
              FETCH FROM c_emp INTO v_date;
          END WHILE;
          CLOSE c_emp;
      END ca
      直接用DELETE語句刪除而不用游標(biāo)被稱作searched delete。像上例這種情況,采用searched delete會比使用positioned delete效率更高。但用positioned delete可以處理更復(fù)雜的邏輯
       
         Positioned Update
        一個用于更新的游標(biāo)(A cursor is updatable)應(yīng)該The cursor is deletable
      >>-UPDATE----+-table-name-------------------+-------------->
                           +-view-name--------------------+
      >-----SET--| assignment-clause |--------------------------->
      >-----WHERE CURRENT OF--cursor-name-----------------------><
      CREATE PROCEDURE upd_raise ( IN p_min DEC(4,2)
                                               , IN p_max DEC(4,2) )
      LANGUAGE SQL
          SPECIFIC upd_raise                        
      ur: BEGIN
          -- Declare variables
          DECLARE v_salary DEC(9,2);
          DECLARE v_bonus  DEC(9,2);
          DECLARE v_comm   DEC(9,2);
          DECLARE v_raise  DEC(4,2);
          -- Declare returncode
          DECLARE SQLSTATE CHAR(5);
          -- Procedure logic
          DECLARE c_emp CURSOR FOR
              SELECT salary, bonus, comm
              FROM employee
              WHERE job!='PRES'
          FOR UPDATE OF salary;                      -- (1)如果只是更新表中的一部分字段,可以利用
                                                                        FOR UPDATE OF <column list>提高效
                                                                 率,讓DB2引擎知道只有這些特定列要UPDATE
          OPEN c_emp;
          FETCH FROM c_emp INTO v_salary, v_bonus, v_comm;
          WHILE ( SQLSTATE = '00000' ) DO
              SET v_raise = p_min;
              IF ( v_bonus >= 600 ) THEN
                  SET v_raise = v_raise + 0.04;
              END IF;
              IF ( v_comm < 2000 ) THEN
                  SET v_raise = v_raise + 0.03;
              ELSEIF ( v_comm < 3000 ) THEN
                  SET v_raise = v_raise + 0.02;
              ELSE
                  SET v_raise = v_raise + 0.01;
              END IF;
              IF ( v_raise > p_max ) THEN
                  SET v_raise = p_max;
              END IF;
              UPDATE employee                                  
                 SET salary = v_salary * (1 + v_raise)
               WHERE CURRENT OF c_emp;
              FETCH FROM c_emp INTO v_salary, v_bonus, v_comm;
          END WHILE;
          CLOSE c_emp;
      END ur
       
          使用游標(biāo)時候的COMMIT和ROLLBACK:
            數(shù)據(jù)庫程序中很重要的一點(diǎn)就是事務(wù)處理(transaction或者the unit of work(UOW))。事務(wù)當(dāng)中的任何一部分失敗,整個事物就會失敗。利用COMMIT和ROLLBACK進(jìn)行適當(dāng)?shù)氖聞?wù)控制對于保證數(shù)據(jù)完整性來說是至關(guān)重要的。
            當(dāng)在使用游標(biāo)的時候使用COMMIT或者ROLLBACK語句時,游標(biāo)的行動取決于是否在生命的時候加了WITH HOLD子句。如果一個游標(biāo)在聲明的時候沒有指定WITH HOLD,那么它的所有資源(游標(biāo),鎖,大對象數(shù)據(jù)類型或者LOB locators)都將在COMMIT或者ROLLBACK之后被釋放。因此,如果需要在完成一個事務(wù)之后使用游標(biāo),就必須重新打開游標(biāo),并從第一行開始執(zhí)行。如果定義了一個游標(biāo)WITH HOLD
      ,游標(biāo)就會在事務(wù)之間保存它的位置和鎖(lock)。需要明白的是,只有保證游標(biāo)位置的鎖被held了。
        鎖(lock)是個數(shù)據(jù)庫對象(a database object),我們用它來控制多個應(yīng)用訪問同一個資源的方式。而一個LOB locator使存儲在本地變量中的4字節(jié)的值,程序可以用它來查到數(shù)據(jù)庫系統(tǒng)中的LOB對象的值
            定義了WITH HOLD的游標(biāo)在COMMIT之后
             1.仍然保證是打開(open)的
             2.游標(biāo)指向下一個滿足條件的行之前
             3.在COMMIT語句之后只允許FETCH和CLOSE
             4.Positioned delete和positioned update只在同一事務(wù)中fetch的行上可用
             5.所有的LOB locators會被釋放
             6.除了保存聲明為WITH HOLD的游標(biāo)位置的鎖,其他鎖都會釋放
             7.當(dāng)執(zhí)行了數(shù)據(jù)修改語句或者含有WITH HOLD游標(biāo)的修改語句被commit的時候
            所有定義為WITH HOLD的游標(biāo)在ROLLBACK之后:
             1.所有游標(biāo)會被關(guān)閉
             2.所有在該事務(wù)中的鎖會被釋放
             3.所有的LOB locators會被freed
      例如:
      CREATE PROCEDURE update_department ( )
          LANGUAGE SQL
          SPECIFIC upd_dept                            
      ud: BEGIN
          -- Declare variable
          DECLARE v_deptno CHAR(3);
          -- Declare returncode
          DECLARE SQLSTATE CHAR(5);
          DECLARE c_dept CURSOR WITH HOLD FOR
              SELECT deptno
              FROM department
          FOR UPDATE OF location;
          -- Declare condition handler
          DECLARE CONTINUE HANDLER FOR SQLSTATE '24504', SQLSTATE '24501'
            L1: LOOP                                                          -- (1)
               LEAVE L1;
            END LOOP;
          -- Procedure logic
          OPEN c_dept;                                                       --打開游標(biāo),指向第一行前面的位置
          FETCH FROM c_dept INTO v_deptno;                                    -- (2)
          UPDATE department SET location='FLOOR1' WHERE CURRENT OF c_dept;    -- (3)
          COMMIT;                                                             -- (4)因?yàn)樵撚螛?biāo)聲明為WITH
                                                                                  HOLD,此時游標(biāo)依舊打開,并且
                                                                                  指向第二行前面的位置。此時表
                                                                                  中第一行的鎖釋放了,且第一行
                                                                                  的值更新為FLOOR1
          FETCH FROM c_dept INTO v_deptno;                                    -- (5)得到第二行數(shù)據(jù),執(zhí)行成功
          COMMIT;                                                             -- (6)COMMIT后游標(biāo)指向第三行之
                                                                                      前的位置,此時并沒有被fetched
          UPDATE department SET location='FLOOR2' WHERE CURRENT OF c_dept;    -- (7)這行
                                                                               命令執(zhí)行失敗,因?yàn)榇藭r游標(biāo)沒有指向
                                                                            任何行,此時游標(biāo)在第二行和第三行之間
          FETCH FROM c_dept INTO v_deptno;                                    -- (8)成功
          UPDATE department SET location='FLOOR3' WHERE CURRENT OF c_dept;    -- (9)成功
          COMMIT;                                                             -- (10)
          FETCH FROM c_dept INTO v_deptno;                                    -- (11)成功
          UPDATE department SET location='FLOOR4' WHERE CURRENT OF c_dept;    -- (12)成
                                                                                  功,此時第三行和第四行的值都變了
          ROLLBACK;                                                           -- (13)第四行的值還原。
                                                                                ROLLBACK之后游標(biāo)關(guān)閉了,
                                                                                所有的鎖也都釋放了
          FETCH FROM c_dept INTO v_deptno;                                    -- (14)錯誤
          UPDATE department SET location='FLOOR5' WHERE CURRENT OF c_dept;    -- (15)
          CLOSE c_dept;
          RETURN 0;
      END ud
      上述存儲過程執(zhí)行前:
      DEPTNO LOCATION
      ------ --------
      A00    -
      B01    -
      C01    -
      D01    -
      D11    -
      上述存儲過程執(zhí)行后:
      DEPTNO LOCATION
      ------ --------
      A00    FLOOR1
      B01    -
      C01    FLOOR3
      D01    -
      D11    -
      如果上例中的游標(biāo)沒有聲明為WITH HOLD,從(5)到(15)的執(zhí)行都會失敗。因?yàn)橛螛?biāo)會在COMMIT或ROLLBACK之后隱性關(guān)閉
       
       
         存儲過程中的Save Points可用于保存事務(wù)回滾的間斷點(diǎn)
      >>- SAVEPOINT--savepoint-name----+--------+--------------------->
                                                          '-UNIQUE-'
      >--ON ROLLBACK RETAIN CURSORS--+--------------------------+----><
                                                        '-ON ROLLBACK RETAIN LOCKS-'
       
      savepoint-name不能以'SYS'開頭,否則會報SQLSTATE 42939的錯誤。UNIQUE選項(xiàng)表示這個save point name不會在Save Point活動期中被reused。ON ROLLBACK RETAIN CURSORS使游標(biāo)在rollback發(fā)生之后還被保留。附加的ON ROLLBACK RETAIN LOCKS防止在ROLLBACK之后鎖丟失
        在一個事務(wù)中,可以定義多個save points
        使用save points的偽代碼:
      savepoint A;
      Do program logic;
      savepoint B;
      Do more program logic;
      savepoint C;
      Do even more program logic;
      之后就可以用含有SAVE POINT的ROLLBACK:ROLLBACK TO SAVEPOINT savepoint-name
      如果ROLLBACK到了最后一個save point,那么這個save point之前的save point都還是活動的(active),你依舊可以ROLL BACK到更早的save point
      例如:
      savepoint a;
      Do program logic;
      savepoint b;
      Do more program logic;
      savepoint c;
      Do even more program logic;
      ROLLBACK TO SAVEPOINT c;           (1)將事務(wù)數(shù)據(jù)返回到save point c
      Do some new logic;
      ROLLBACK TO SAVEPOINT a;           (2)將事務(wù)數(shù)據(jù)返回到save point a
      Do some more logic;
      ROLLBACK TO SAVEPOINT b;           (3)錯誤,因?yàn)榇藭rsave point b已經(jīng)不存在了
       
      游標(biāo)除了可以在存儲過程中處理數(shù)據(jù)外,還可以用于返回結(jié)果集
      比如:
      CREATE PROCEDURE read_emp ( )
          LANGUAGE SQL
          SPECIFIC read_emp                           
      DYNAMIC RESULT SETS 1                            --(1)如果想用游標(biāo)返回結(jié)果集到一個應(yīng)用程序,必須聲明DYNAMIC RESULT SETS
      re: BEGIN
          -- Procedure logic
          DECLARE c_emp CURSOR WITH RETURN FOR         --(2)
              SELECT salary, bonus, comm
              FROM employee
              WHERE job!='PRES';
          OPEN c_emp;                                  --(3)為客戶端保持游標(biāo)打開
      END re
      此時只返回了所有符合條件的員工的salary, bonus和commission字段。之后,結(jié)果集就可以被另外的存儲過程或客戶端程序調(diào)用
         
          在存儲過程中我們除了數(shù)據(jù)操作語言(Data Manipulation Language (DML):SELECT, DELETE和UPDATE),還可以使用數(shù)據(jù)定義語言(Data Definition Language (DDL)),比如定義一個表。我們可以在存儲過程中定義一個表,然后用游標(biāo)返回結(jié)果集。但是游標(biāo)聲明必須在BEGIN ... END的一開始,但如果這樣的話,此時表還沒有建立,編譯時會報錯。但如果先聲明表,編譯也會報錯。這是我們可以用BEGIN ... END可以嵌套這個特性。我們在存儲過程末尾嵌套一個BEGIN ... END來聲明游標(biāo)
      如:
      CREATE PROCEDURE create_and_return ( )
          LANGUAGE SQL
          SPECIFIC create_and_return                  
      DYNAMIC RESULT SETS 1
      cr: BEGIN
          -- Procedure logic
          CREATE TABLE mytable (sid INT);
          INSERT INTO mytable VALUES (1);
          INSERT INTO mytable VALUES (2);
          BEGIN                                        --(1)
          DECLARE c_cur CURSOR WITH RETURN
              FOR SELECT *
                  FROM mytable;
          OPEN c_cur;                                  --(2)
          END;                                         --(3)OPEN必須在這個嵌套的BEGIN ... END中,因?yàn)橛?/div>
                                                            標(biāo)的定義只在這個BEGIN ... END中有效
      END cr
         
          有時我們不只返回一個結(jié)果集,若返回多個結(jié)果集,要求:
           1.CREATE PROCEDURE中的DYNAMIC RESULT SETS子句寫明想返回的結(jié)果集的數(shù)量
           2.為每一個結(jié)果集聲明含有WITH RETURN的游標(biāo)
           3.保證所有游標(biāo)返回給客戶端是打開的
       例如:
      CREATE PROCEDURE read_emp_multi ( )
          LANGUAGE SQL
          SPECIFIC read_emp_multi               
          DYNAMIC RESULT SETS 3                  --(1)
      re: BEGIN
          -- Procedure logic
          DECLARE c_salary CURSOR WITH RETURN FOR
              SELECT salary
                FROM employee;
          DECLARE c_bonus CURSOR WITH RETURN FOR
              SELECT bonus
                FROM employee;
          DECLARE c_comm CURSOR WITH RETURN FOR
              SELECT comm
                FROM employee;
          OPEN c_salary;
          OPEN c_bonus;
          OPEN c_comm;
      END re
      游標(biāo)打開的順序反映了結(jié)果集返回給客戶端的順序
          當(dāng)在存儲過程中使用游標(biāo)的時候,會影響其他應(yīng)用和人們使用這個數(shù)據(jù)庫。鎖的類型取決于游標(biāo)的類型和DB2的隔離級別(isolation level)
       
          鎖模式(Lock Modes):
      Table  Row Lock Descriptions

      Lock Mode

      Applicable Object Type

      Description

      S (Share)

      Rows, blocks, tables

      The lock owner and all concurrent applications can read, but not update, the locked data.

      U (Update)

      Rows, blocks, tables

      The lock owner can update data. Other UOW can read the data in the locked object, but cannot attempt to update it.

      X (Exclusive)

      Rows, blocks, tables, bufferpools

      The lock owner can both read and update data in the locked object. Only uncommitted read applications can access the locked object.


      除非迫不得已不要用游標(biāo)

              不管是sql server 還是 oracle都提供了游標(biāo),其一般用途就是從查詢結(jié)構(gòu)中遍歷數(shù)據(jù)。游標(biāo)很好用,許多初學(xué)oracle或者sql server的程序員都喜歡用,然而如果濫用游標(biāo)的話,對程序的性能會造成很大的影響。我認(rèn)為:除非不得已,不要使用游標(biāo)。下面是我的一次優(yōu)化經(jīng)歷。
      問題:
              在我們的系統(tǒng)中,需要管理產(chǎn)品模型,對PDM了解的人知道,其實(shí)產(chǎn)品模型可以當(dāng)作一個特殊的零部件來處理,所以在數(shù)據(jù)表的時候產(chǎn)品模型與零部件使用相同的數(shù)據(jù)表來存放數(shù)據(jù),只不過是用一個flag來標(biāo)示是零部件還是產(chǎn)品模型。產(chǎn)品模型具有版本?,F(xiàn)在的要求的是查出最新的所有的零部件信息,查詢的時候允許用戶自定義查詢條件。
              用戶自定義查詢條件是從界面上通過各種選項(xiàng)來構(gòu)造的,因此傳遞的是動態(tài)SQL語句,為了提高效率數(shù)據(jù)庫上建立了一個存儲過程專門來查詢產(chǎn)品模型。下面是一個初學(xué)oracle不久的編程人員編寫的存儲過程:

       1PROCEDURE GETPRODMODELBYSQL(p_sql        IN VARCHAR2,                 
       2                               cur_mi_prodmodel OUT SYS_BASE.BASECURSOR) AS
       3   sqlstr varchar2(1000);
       4   idstr  varchar2(1000);
       5   
       6   
       7   dis_id number;
       8   maxver number;
       9        cursor disid_curs is
      10              select distinct pt_id
      11              from mi_part
      12              where pt_flag = 2;                               
      13   BEGIN
      14    open disid_curs;
      15         loop
      16             fetch disid_curs
      17             into dis_id;
      18             exit when disid_curs% notfound;
      19             
      20             select max(pv_id)
      21             into maxver
      22             from mi_partver
      23             where pv_partid = dis_id;
      24             
      25             if maxver is null then
      26                 idstr := idstr;
      27             else
      28                 idstr := idstr || maxver || ',';
      29             end if;
      30          end loop;
      31
      32          idstr  := rtrim(idstr, ',');
      33          idstr  := ltrim(idstr, ',');
      34          if idstr is null then
      35              sqlstr := p_sql || ' ORDER BY PV_PRODUCTID,PT_PARTNUMBER';
      36          else
      37              sqlstr := p_sql || ' and MI_PARTVER.pv_id in (' || idstr || ')  ORDER BY PV_PRODUCTID,PT_PARTNUMBER';
      38           end if;
      39
      40        open cur_mi_prodmodel for sqlstr;
      41   END GETPRODMODELBYSQL;

      這個存儲過程可以正常工作,但是其速度執(zhí)行起來非常慢,如果數(shù)據(jù)表中有很多數(shù)據(jù)的話,其速度很可能是直線下降,究其原因是因?yàn)槭褂糜螛?biāo)來遍歷然后構(gòu)造查詢語句。對這個存儲過程進(jìn)行優(yōu)化:
       1PROCEDURE GETPRODMODELBYSQL(p_sql        IN VARCHAR2,                 
       2                               cur_mi_prodmodel OUT SYS_BASE.BASECURSOR) AS
       3   s varchar2(300);
       4   sqlstr varchar2(1000);
       5   /*idstr  varchar2(1000);
       6   
       7   
       8   dis_id number;
       9   maxver number;
      10        cursor disid_curs is
      11              select distinct pt_id
      12              from mi_part
      13              where pt_flag = 2;  */
                                   
      14   BEGIN
      15    /*open disid_curs;
      16         loop
      17             fetch disid_curs
      18             into dis_id;
      19             exit when disid_curs% notfound;
      20             
      21             select max(pv_id)
      22             into maxver
      23             from mi_partver
      24             where pv_partid = dis_id;
      25             
      26             if maxver is null then
      27                 idstr := idstr;
      28             else
      29                 idstr := idstr || maxver || ',';
      30             end if;
      31          end loop;*/

      32          s:=' and MI_PARTVER.pv_id in (select a.pv_id from mi_partver a,mi_part c where a.pv_partid = c.pt_id and c.pt_flag =2 and
      33a.pv_id in (select e.pv_id from mi_partver e
      34where e.pv_id in (select max(b.pv_id) from mi_partver b where e.pv_partid = b.pv_partid)))';
      35          /*idstr  := rtrim(idstr, ',');
      36          idstr  := ltrim(idstr, ',');
      37          if idstr is null then
      38              sqlstr := p_sql || ' ORDER BY PV_PRODUCTID,PT_PARTNUMBER';
      39          else
      40              sqlstr := p_sql || ' and MI_PARTVER.pv_id in (' || idstr || ')  ORDER BY PV_PRODUCTID,PT_PARTNUMBER';
      41           end if;*/

      42              sqlstr := p_sql || s ||  'ORDER BY PV_PRODUCTID,PT_PARTNUMBER';
      43        open cur_mi_prodmodel for sqlstr;
      44   END GETPRODMODELBYSQL;

      這里的有效語句是使用查詢語句來構(gòu)造查詢,其結(jié)果是速度得到了數(shù)量級的提高,而且避免了一個隱患就是緩沖區(qū)溢出,因?yàn)樵瓉淼拇鎯^程中定義了幾個varchar2(1000)的變量,實(shí)際上這個變量的上界是不可以預(yù)期的,而緩沖區(qū)溢出也是很多初學(xué)oracle的程序員經(jīng)常忽略甚至想不到的問題。
       

      SQLServer 游標(biāo)簡介與使用說明

            游標(biāo)(Cursor)是處理數(shù)據(jù)的一種方法,為了查看或者處理結(jié)果集中的數(shù)據(jù),游標(biāo)提供了在結(jié)果集中一次以行或者多行前進(jìn)或向后瀏覽數(shù)據(jù)的能力。我們可以把游標(biāo)當(dāng)作一個指針,它可以指定結(jié)果中的任何位置,然后允許用戶對指定位置的數(shù)據(jù)進(jìn)行處理。

            1.游標(biāo)的組成

            游標(biāo)包含兩個部分:一個是游標(biāo)結(jié)果集、一個是游標(biāo)位置。

            游標(biāo)結(jié)果集:定義該游標(biāo)得SELECT語句返回的行的集合。游標(biāo)位置:指向這個結(jié)果集某一行的當(dāng)前指針。

       

            2.游標(biāo)的分類

            游標(biāo)共有3類:API服務(wù)器游標(biāo)、Transaction-SQL游標(biāo)和API客戶端游標(biāo)。

            其中前兩種游標(biāo)都是運(yùn)行在服務(wù)器上的,所以又叫做服務(wù)器游標(biāo)。

            API服務(wù)器游標(biāo)

            API服務(wù)器游標(biāo)主要應(yīng)用在服務(wù)上,當(dāng)客戶端的應(yīng)用程序調(diào)用API游標(biāo)函數(shù)時,服務(wù)器會對API函數(shù)進(jìn)行處理。使用API函數(shù)和方法可以實(shí)現(xiàn)如下功能:

            (1)打開一個連接。

            (2)設(shè)置定義游標(biāo)特征的特性或?qū)傩?,API自動將游標(biāo)影射到每個結(jié)果集。

            (3)執(zhí)行一個或多個Transaction-SQL語句。

            (4)使用API函數(shù)或方法提取結(jié)果集中的行。

            API服務(wù)器游標(biāo)包含以下四種:靜態(tài)游標(biāo)、動態(tài)游標(biāo)、只進(jìn)游標(biāo)、鍵集驅(qū)動游標(biāo)(Primary key)

            靜態(tài)游標(biāo)的完整結(jié)果集將打開游標(biāo)時建立的結(jié)果集存儲在臨時表中,(靜態(tài)游標(biāo)始終是只讀的)。靜態(tài)游標(biāo)具有以下特點(diǎn):總是按照打開游標(biāo)時的原樣顯示結(jié)果集;不反映數(shù)據(jù)庫中作的任何修改,也不反映對結(jié)果集行的列值所作的更改;不顯示打開游標(biāo)后在數(shù)據(jù)庫中新插入的行;組成結(jié)果集的行被其他用戶更新,新的數(shù)據(jù)值不會顯示在靜態(tài)游標(biāo)中;但是靜態(tài)游標(biāo)會顯示打開游標(biāo)以后從數(shù)據(jù)庫中刪除的行。

            動態(tài)游標(biāo)與靜態(tài)游標(biāo)相反,當(dāng)滾動游標(biāo)時動態(tài)游標(biāo)反映結(jié)果集中的所有更改。結(jié)果集中的行數(shù)據(jù)值、順序和成員每次提取時都會改變。

            只進(jìn)游標(biāo)不支持滾動,它只支持游標(biāo)從頭到尾順序提取數(shù)據(jù)行。注意:只進(jìn)游標(biāo)也反映對結(jié)果集所做的所有更改。

            鍵集驅(qū)動游標(biāo)同時具有靜態(tài)游標(biāo)和動態(tài)游標(biāo)的特點(diǎn)。當(dāng)打開游標(biāo)時,該游標(biāo)中的成員以及行的順序是固定的,鍵集在游標(biāo)打開時也會存儲到臨時工作表中,對非鍵集列的數(shù)據(jù)值的更改在用戶游標(biāo)滾動的時候可以看見,在游標(biāo)打開以后對數(shù)據(jù)庫中插入的行是不可見的,除非關(guān)閉重新打開游標(biāo)。

       

            Transaction-SQL游標(biāo)

            該游標(biāo)是基于Declare Cursor 語法,主要用于Transaction-SQL腳本、存儲過程以及觸發(fā)器中。Transaction-SQL游標(biāo)在服務(wù)器處理由客戶端發(fā)送到服務(wù)器的Transaction-SQL語句。

            在存儲過程或觸發(fā)器中使用Transaction-SQL游標(biāo)的過程為:

            (1)聲明Transaction-SQL變量包含游標(biāo)返回的數(shù)據(jù)。為每個結(jié)果集列聲明一個變量。聲明足夠大的變量來保存列返回的值,并聲明變量的類型為可從數(shù)據(jù)類型隱式轉(zhuǎn)換得到的數(shù)據(jù)類型。

            (2)使用Declare Cursor語句將Transaction-SQL游標(biāo)與Select語句相關(guān)聯(lián)。還可以利用Declare Cursor定義游標(biāo)的只讀、只進(jìn)等特性?!?/p>

            (3)使用Open語句執(zhí)行Select語句填充游標(biāo)。

            (4)使用Fetch Into語句提取單個行,并將每列中得數(shù)據(jù)移至指定的變量中。注意:其他Transaction-SQL語句可以引用那些變量來訪問提取的數(shù)據(jù)值。Transaction-SQL游標(biāo)不支持提取行塊。

            (5)使用Close語句結(jié)束游標(biāo)的使用。注意:關(guān)閉游標(biāo)以后,該游標(biāo)還是存在,可以使用Open命令打開繼續(xù)使用,只有調(diào)用Deallocate語句才會完全釋放。

            客戶端游標(biāo)

            該游標(biāo)將使用默認(rèn)結(jié)果集把整個結(jié)果集高速緩存在客戶端上,所有的游標(biāo)操作都在客戶端的高速緩存中進(jìn)行。注意:客戶端游標(biāo)只支持只進(jìn)和靜態(tài)游標(biāo)。不支持其他游標(biāo)。

       

            3.游標(biāo)的生命周期

            游標(biāo)的生命周期包含有五個階段:聲明游標(biāo)、打開游標(biāo)、讀取游標(biāo)數(shù)據(jù)、關(guān)閉游標(biāo)、釋放游標(biāo)。

            聲明游標(biāo)是為游標(biāo)指定獲取數(shù)據(jù)時所使用的Select語句,聲明游標(biāo)并不會檢索任何數(shù)據(jù),它只是為游標(biāo)指明了相應(yīng)的Select 語句。

            Declare 游標(biāo)名稱 Cursor 參數(shù)

            聲明游標(biāo)的參數(shù)

                  (1)Local與Global:Local表示游標(biāo)的作用于僅僅限于其所在的存儲過程、觸發(fā)器以及批處理中、執(zhí)行完畢以后游標(biāo)自動釋放。Global表示的是該游標(biāo)作用域是整個會話層。由連接執(zhí)行的任何存儲過程、批處理等都可以引用該游標(biāo)名稱,僅在斷開連接時隱性釋放。

                  (2)Forward_only與Scroll:前者表示為只進(jìn)游標(biāo),后者表示為可以隨意定位。默認(rèn)為前者。

                  (3)Static、Keyset與Dynamic: 第一個表示定義一個游標(biāo),其數(shù)據(jù)存放到一個臨時表內(nèi),對游標(biāo)的所有請求都從臨時表中應(yīng)答,因此,對該游標(biāo)進(jìn)行提取操作時返回的數(shù)據(jù)不反映對基表所作的修改,并且該游標(biāo)不允許修改。Keyset表示的是,當(dāng)游標(biāo)打開時,鍵集驅(qū)動游標(biāo)中行的身份與順序是固定的,并把其放到臨時表中。Dynamic表示的是滾動游標(biāo)時,動態(tài)游標(biāo)反映對結(jié)果集內(nèi)所有數(shù)據(jù)的更改。

                  (4)Read_only 、Scroll_Locks與Optimistic:第一個表示的是只讀游標(biāo),第二個表示的是在使用的游標(biāo)結(jié)果集數(shù)據(jù)上放置鎖,當(dāng)行讀取到游標(biāo)中然后對它們進(jìn)行修改時,數(shù)據(jù)庫將鎖定這些行,以保證數(shù)據(jù)的一致性。Optimistic的含義是游標(biāo)將數(shù)據(jù)讀取以后,如果這些數(shù)據(jù)被更新了,則通過游標(biāo)定位進(jìn)行的更新與刪除操作將不會成功。

            標(biāo)準(zhǔn)游標(biāo):

                  Declare MyCursor Cursor 
                         For Select * From Master_Goods

            只讀游標(biāo)

                  Declare MyCusror Cursor

                        For Select * From Master_Goods

                        For Read Only

            可更新游標(biāo)

                  Declare MyCusror Cursor

                        For Select * From Master_Goods

                        For UpDate

            打開游標(biāo)使用Open語句用于打開Transaction-SQL服務(wù)器游標(biāo),執(zhí)行Open語句的過程中就是按照Select語句進(jìn)行填充數(shù)據(jù),打開游標(biāo)以后游標(biāo)位置在第一行。

            打開游標(biāo)

                  全局游標(biāo):Open Global MyCursor            局部游標(biāo): Open MyCursor

            讀取游標(biāo)數(shù)據(jù):在打開游標(biāo)以后,使用Fetch語句從Transaction-SQL服務(wù)器游標(biāo)中檢索特定的一行。使用Fetch操作,可以使游標(biāo)移動到下一個記錄,并將游標(biāo)返回的每個列得數(shù)據(jù)分別賦值給聲明的本地變量。

                  Fetch [Next | Prior | First | Last | Absolute n | Relative n ]  From MyCursor

                  Into @GoodsID,@GoodsName

                  其中:Next表示返回結(jié)果集中當(dāng)前行的下一行記錄,如果第一次讀取則返回第一行。默認(rèn)的讀取選項(xiàng)為Next

                         Prior表示返回結(jié)果集中當(dāng)前行的前一行記錄,如果第一次讀取則沒有行返回,并且把游標(biāo)置于第一行之前。

                         First表示返回結(jié)果集中的第一行,并且將其作為當(dāng)前行。

                         Last表示返回結(jié)果集中的最后一行,并且將其作為當(dāng)前行。

                         Absolute n 如果n為正數(shù),則返回從游標(biāo)頭開始的第n行,并且返回行變成新的當(dāng)前行。如果n為負(fù),則返回從游標(biāo)末尾開始的第n行,并且返回行為新的當(dāng)前行,如果n為0,則返回當(dāng)前行。

                         Relative n 如果n為正數(shù),則返回從當(dāng)前行開始的第n行,如果n為負(fù),則返回從當(dāng)前行之前的第n行,如果為0,則返回當(dāng)前行。

            關(guān)閉游標(biāo)調(diào)用的是Close語句,方式如下:Close Global MyCursor               Close MyCursor

            釋放游標(biāo)調(diào)用的是Deallocate語句,方法如下:Deallocate Glboal MyCursor       Deallocate MyCursor

       

            游標(biāo)實(shí)例:

                  Declare MyCusror Cursor Scroll

                        For Select * From Master_Goods Order By GoodsID

                  Open MyCursor

                  Fetch next From MyCursor
                  Into @GoodsCode,@GoodsName

                  While(@@Fetch_Status = 0)
                        Begin

                               Begin
                                     Select @GoodsCode = Convert(Char(20),@GoodsCode)
                                     Select @GoodsName = Convert(Char(20),@GoodsName)
                                     PRINT @GoodsCode + ':' + @GoodsName
                               End

                               Fetch next From MyCursor
                               Into @GoodsCode,@GoodsName

                        End
                  Close MyCursor
                  Deallocate MyCursor

       

            修改當(dāng)前游標(biāo)的數(shù)據(jù)方法如下:

                  UpDate Master_Goods Set GoodsName = 'yangyang8848' Where Current Of MyCursor;
            刪除當(dāng)前游標(biāo)行數(shù)據(jù)的方法如下: 
                  Delete From Master_Goods Where Current Of MyCursor

       

            Select @@CURSOR_ROWS 可以得到當(dāng)前游標(biāo)中存在的數(shù)據(jù)行數(shù)。注意:此變量為一個連接上的全局變量,因此只對應(yīng)最后一次打開的游標(biāo)。

      游標(biāo)例子

      select * from dbo.Products

      select * from dbo.Orders

      select * from [Order Details]

      select * from dbo.Categories Select b.ProductID,datepart(Year,a.OrderDate) as [Year],datepart(Month,a.OrderDate) as [Month],Sum(b.Quantity) as Quantity, c.ProductName,Count(a.OrderID) as Orders from Orders a Inner Join [Order Details] b On a.OrderID = b.OrderID Inner Join Products c On b.ProductID=c.ProductID Group By b.ProductID,a.OrderDate,c.ProductName Order by b.ProductID Asc,a.OrderDate Asc go

      --第一題

      Alter PROCEDURE USP_Product1 AS BEGIN DECLARE @ID int,@TempID int DECLARE @ProductName NVARCHAR(50) DECLARE @Year NVARCHAR(4) DECLARE @Month NVARCHAR(2) DECLARE @OrderCount int DECLARE @DetailsCount int DECLARE @TotalCount int DECLARE @TotalDetails int DECLARE Cursor_Product CURSOR LOCAL FOR

      --STEP1 聲明游標(biāo) Select b.ProductID,datepart(Year,a.OrderDate) as [Year],datepart(Month,a.OrderDate) as [Month],Sum(b.Quantity) as Quantity, c.ProductName,Count(a.OrderID) as Orders from Orders a Inner Join [Order Details] b On a.OrderID = b.OrderID Inner Join Products c On b.ProductID=c.ProductID Group By b.ProductID,a.OrderDate,c.ProductName Order by b.ProductID Asc,a.OrderDate Asc FOR READ ONLY

      CREATE TABLE #ProductDetails (產(chǎn)品編號 INT ,產(chǎn)品名稱 NVARCHAR(50),月份 NVARCHAR(10),訂單總數(shù) INT,出貨總量 INT)

      --創(chuàng)建臨時表 set @TempID=null --判斷是否為同一個商品 set @TotalCount = 0 set @TotalDetails = 0 OPEN Cursor_Product

      --STEP2 打開游標(biāo) WHILE(1=1) BEGIN

      --STEP3 從游標(biāo)中提取行 FETCH NEXT FROM Cursor_Product INTO @ID,@Year,@Month,@DetailsCount,@ProductName,@OrderCount IF(@@FETCH_STATUS<>0)BREAK

      --跳出循環(huán) if @TempID is null

      --判斷是第一次的話為@TempID賦值 BEGIN set @TempID=@ID END if @TempID<>@ID

      --判斷是否需要插入小計 BEGIN insert into #ProductDetails Values(null,null,N'小計:',@TotalCount,@TotalDetails) set @TotalCount = 0 set @TotalDetails = 0 set @TempID=@ID Continue

      --跳入下次循環(huán) END set @TotalCount = @TotalCount+@OrderCount set @TotalDetails = @TotalDetails+@DetailsCount insert into #ProductDetails Values(@ID,@ProductName,Convert(Nvarchar(50),@Year)+N'年'+Convert(Nvarchar(50),@Month)+N'月',@OrderCount,@DetailsCount) END select * from #ProductDetails CLOSE Cursor_Product

      --STEP4 關(guān)閉游標(biāo) DEALLOCATE Cursor_Product

       --STEP5 釋放游標(biāo) END GO EXEC USP_Product1 -- DROP Proc USP_Product1 GO Select c.ProductName,Count(a.OrderID) as Orders,SUM(c.UnitPrice*b.Quantity) as Price from Orders a Inner Join [Order Details] b On a.OrderID = b.OrderID Inner Join Products c On b.ProductID=c.ProductID Where c.CategoryID=1 Group By c.ProductName Order by c.ProductName Asc Go

      --第二題 Alter PROCEDURE USP_Product2 AS BEGIN DECLARE @ID int,@Temp int DECLARE @CategoryName NVARCHAR(50) DECLARE @ProductName NVARCHAR(50) DECLARE @POCount int DECLARE @POPrices money --小計 DECLARE @OrderCount int DECLARE @OrderPrices money --總計 DECLARE @Orders int DECLARE @Prices money

      -- 聲明游標(biāo)1 DECLARE Cursor_Categories CURSOR LOCAL FOR select CategoryID,CategoryName from Categories FOR READ ONLY CREATE TABLE #ProductDetails (產(chǎn)品類別 INT ,類別名稱 NVARCHAR(50),產(chǎn)品名稱 NVARCHAR(50),下單總次數(shù) INT,下單總價格 INT)

      --創(chuàng)建臨時表 --小計 SET @OrderCount = 0 SET @OrderPrices = 0

      --總計 SET @Orders = 0 SET @Prices = 0 OPEN Cursor_Categories

      -- 打開游標(biāo)1 WHILE(1=1) BEGIN

      -- 從游標(biāo)1中提取行 FETCH NEXT FROM Cursor_Categories INTO @ID,@CategoryName IF(@@FETCH_STATUS<>0)BREAK

      --跳出循環(huán) DECLARE Cursor_Product CURSOR LOCAL FOR

      -- 聲明游標(biāo)2 Select c.ProductName,Count(a.OrderID) as Orders,SUM(c.UnitPrice*b.Quantity) as Price from Orders a Inner Join [Order Details] b On a.OrderID = b.OrderID Inner Join Products c On b.ProductID=c.ProductID Where c.CategoryID=@ID Group By c.ProductName Order by c.ProductName Asc FOR READ ONLY Set @Temp = null OPEN Cursor_Product

      -- 打開游標(biāo)2 WHILE(1=1) BEGIN FETCH NEXT FROM Cursor_Product INTO @ProductName,@POCount,@POPrices IF(@@FETCH_STATUS<>0)BREAK

      --跳出循環(huán) if(@Temp is Null) -- 第一次進(jìn)入 BEGIN SET @Temp=1 SET @OrderCount=@POCount SET @OrderPrices=@POPrices Insert Into #ProductDetails Values(@ID,@CategoryName,@ProductName,@POCount,@POPrices) END Else BEGIN SET @OrderCount= @OrderCount + @POCount SET @OrderPrices= @OrderPrices + @POPrices Insert Into #ProductDetails(產(chǎn)品名稱,下單總次數(shù),下單總價格) Values(@ProductName,@POCount,@POPrices) END END Insert Into #ProductDetails(產(chǎn)品名稱,下單總次數(shù),下單總價格) Values('小計:',@OrderCount,@OrderPrices)

      --累加總計 SET @Orders = @Orders + @OrderCount SET @Prices = @Prices + @OrderPrices CLOSE Cursor_Product

      -- 關(guān)閉游標(biāo)2 DEALLOCATE Cursor_Product

      -- 釋放游標(biāo)2 END Insert Into #ProductDetails(產(chǎn)品名稱,下單總次數(shù),下單總價格) Values('總計:',@Orders,@Prices) select * from #ProductDetails CLOSE Cursor_Categories

      -- 關(guān)閉游標(biāo)1 DEALLOCATE Cursor_Categories

      -- 釋放游標(biāo)1 END GO EXEC USP_Product2 -- DROP PROC USP_Product2

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多