ORACLE - <一战通> - 游标

目录

一,游标

1,游标是什么

2,显式游标与隐式游标的区别

3,游标的四个属性

二,显式游标

1,显示游标的语法

2,游标的FOR循环

  1)语法

3,例子

1)获取信息--查询所有TEXT_TABLE的信息。

2)游标属性的用法

3)简化游标,游标的FOR循环(简化下loop循环的游标操作)

三,隐式游标

1,隐式游标简介

2,例子

四,游标修改和删除

1,使用游标进行数据操作

2,NOWAIT  -- 不等待锁

3,OF子句  --  共享锁

4,参数游标

5,例子

1)按逻辑,分别修改参数--LOOP

2)按逻辑,分别修改参数--FOR

3)定义游标时利用FOR UPDATE 子句可以将游标提取出来的数据进行行级锁定

4)使用NOWAIT

5)使用OF字句在特定表上加共享锁(带有参数的游标)


一,游标

1,游标是什么

    是SQL的一个内存工作区,由系统或用户以变量的方式定义。临时存储从数据库中提取的数据块。是一个结果集。

2,显式游标与隐式游标的区别

    显式游标:select返回的多行数据

    隐式游标

    显式游标是用户自定义的显式创建的游标,主要是用于对查询语句的处理。

    隐式游标是由系统隐含创建的游标。主要用于对非查询语句,如修改,删除等操作,

    则有oracle系统自动地为这些操作设置游标并创建其工作区,对于隐式游标的操作,

    如定义,打开,取值及关闭操作,都有oralce系统自动完成,无需用户进行处理。

    隐式游标的名字为SQL,这是由oracle系统定义的。

 

3,游标的四个属性

%FOUND     :监测游标结果集是否存在数据,存在=true

%NOTFOUND :监测游标结果集是否不存在数据,不存在=true

%ISOPEN    :监测游标是否打开,打开=true

%ROWCOUNT :返回已提取的实际行数。

 

二,显式游标

 

1,显示游标的语法

--1定义游标
CURSOR CURSOR_NAME [(paramenter_name datatype)]
IS select_sql;

--2打开游标    游标结果集
OPEN CURSOR_NAME;

--3提取数据    每次只能提取一行
FETCH CURSOR_NAME INTO variable1[,variable2...];

PL/SQL变量

--4关闭游标
CLOSE CURSOR_NAME;

 

2,游标的FOR循环

     当时用游标FOR时,oracle会隐含的打开游标,提取数据并关闭游标。

     当进入循环时,游标FOR循环语句自动打开游标,并提取第一行游标数据;

     当程序处理完当前所提取的数据而进入下一次循环时,游标FOR循环语句自动提取下一行数据供程序处理;

     当提取完结果集合中的所有数据行后结束循环,并自动关闭游标。

  1)语法

FOR  record_name IN cursor_name LOOP

     statement;

END LOOP;

 

3,例子

1)获取信息--查询所有TEXT_TABLE的信息。

效果

ID:1,NAME:1
ID:3,NAME:3
ID:4,NAME:4
ID:5,NAME:5
ID:2,NAME:2
ID:2,NAME:2

2)游标属性的用法

DECLARE
  --定义游标
  CURSOR emp_cursor IS SELECT ID,NAME from TEXT_TABLE ;
  V_ID    TEXT_TABLE.ID%TYPE;
  V_NAME TEXT_TABLE.NAME%TYPE;
  V_STR   varchar2(50);
BEGIN

  IF  emp_cursor%ISOPEN THEN
          V_STR  := V_STR||'ISOPEN=true  ';
  ELSE
          V_STR  := V_STR||'ISOPEN=false  ';     
  END IF;  
  DBMS_OUTPUT.PUT_LINE(V_STR);
  --打开游标,执行查询
  OPEN emp_cursor;
  --提取数据  
  LOOP
       FETCH emp_cursor INTO V_ID,V_NAME;
           V_STR := '   ';
           IF  emp_cursor%FOUND THEN
              V_STR  := V_STR||'FOUND=true  ';
           ELSE
              V_STR  := V_STR||'FOUND=false  ';
           END IF;    
           IF  emp_cursor%NOTFOUND THEN
              V_STR  := V_STR||'NOTFOUND=true  ';
           ELSE
              V_STR  := V_STR||'NOTFOUND=false  ';  
           END IF;    
           IF  emp_cursor%ISOPEN THEN
              V_STR  := V_STR||'ISOPEN=true  ';
           ELSE
              V_STR  := V_STR||'ISOPEN=false  ';     
           END IF;    
           DBMS_OUTPUT.PUT_LINE('ID:'||V_ID||',NAME:'||V_NAME ||'  ROWCOUNT:'|| emp_cursor%ROWCOUNT||V_STR);
            
       --什么时候能够退出循环?
       --%FOUND,%NOTFOUND  有记录返回true,没记录返回true
       EXIT WHEN emp_cursor%NOTFOUND;       
  END LOOP;
  --关闭游标
  CLOSE emp_cursor;
  
  IF  emp_cursor%ISOPEN THEN
          DBMS_OUTPUT.PUT_LINE('ISOPEN=true  ');
  ELSE   
          DBMS_OUTPUT.PUT_LINE('ISOPEN=false  ');
  END IF;  
END;

效果

ISOPEN=false  
ID:1,NAME:1  ROWCOUNT:1   FOUND=true  NOTFOUND=false  ISOPEN=true  
ID:3,NAME:3  ROWCOUNT:2   FOUND=true  NOTFOUND=false  ISOPEN=true  
ID:4,NAME:4  ROWCOUNT:3   FOUND=true  NOTFOUND=false  ISOPEN=true  
ID:5,NAME:5  ROWCOUNT:4   FOUND=true  NOTFOUND=false  ISOPEN=true  
ID:2,NAME:2  ROWCOUNT:5   FOUND=true  NOTFOUND=false  ISOPEN=true  
ID:2,NAME:2  ROWCOUNT:5   FOUND=false  NOTFOUND=true  ISOPEN=true  
ISOPEN=false  

 

3)简化游标,游标的FOR循环(简化下loop循环的游标操作)

 

DECLARE
  --定义游标
  CURSOR emp_cursor IS SELECT ID,NAME from TEXT_TABLE ;
BEGIN
  FOR  emp IN emp_cursor LOOP
           DBMS_OUTPUT.PUT_LINE('ID:'||emp.ID||',NAME:'||emp.NAME ||'  ROWCOUNT:'|| emp_cursor%ROWCOUNT);
  END LOOP;
END;


--定义游标FOR循环引用子查询
BEGIN
  FOR  emp IN (SELECT ID,NAME from TEXT_TABLE ) LOOP
           DBMS_OUTPUT.PUT_LINE('ID:'||emp.ID||',NAME:'||emp.NAME ||'  ROWCOUNT:');
  END LOOP;
END;

效果

ID:1,NAME:1  ROWCOUNT:1
ID:3,NAME:3  ROWCOUNT:2
ID:4,NAME:4  ROWCOUNT:3
ID:5,NAME:5  ROWCOUNT:4
ID:2,NAME:2  ROWCOUNT:5

 

三,隐式游标

1,隐式游标简介

    当系统使用一个隐式游标时,可以通过隐式游标的属性来了解操作的状态和结果,进而控制程序的流程。通过SQL游标名总是只能访问前一个DML操作或单行SELECT操作的游标属性。

       DML操作和单行SELECT语句会使用隐式游标

       插入操作:INSERT

       更新操作:UODATE

       删除操作:DELETE

      单行查询操作:SELECT ... INTO

 

 

2,例子

--隐式游标
BEGIN

  UPDATE TEXT_TABLE SET NAME='11' WHERE ID = '1';

  IF SQL%FOUND THEN

    DBMS_OUTPUT.put_line('修改成功');
    COMMIT;

  ELSE

    DBMS_OUTPUT.put_line('修改失败!');
    ROLLBACK;

  END IF;

END;

SELECT * FROM TEXT_TABLE;

 

四,游标修改和删除

 

1,使用游标进行数据操作

 

      对了对正在处理(查询)的行不被另外的用户改动,oracle提供一个FOR UPDATE 字句来对所选择的行进行锁住。

    (针对不同操作所表现出来的效果也不一样

     删除未提交        查询会卡住(死锁)

     修改未提交        查询会卡住(死锁)

     新增未提交        新插入的数据无法查询出来

 

2,NOWAIT  -- 不等待锁

    用于指定不等待锁,如果发现所操作的数据行已经锁定,将不会等待,立即返回。可以避免死锁。

 

3,OF子句  --  共享锁

    使用OF子句在特定表上加共享锁,当游标子查询涉及到多张表时,如果在特定表上加行共享锁,那么需要使用OF子句。

 

4,参数游标

   是指带有参数的游标,通过使用参数游标,使用不同的参数值可以生成不同的游标结果集。

语法

CURSOR  cursor_name(parameter_name datatype)  IS

        select_sql;

OPEN  cursor_name(pararmeter_value);

 

5,例子

1)按逻辑,分别修改参数--LOOP

DECLARE
  --定义游标
  CURSOR emp_cursor IS SELECT ID,NAME from TEXT_TABLE ;
  V_ID    TEXT_TABLE.ID%TYPE;
  V_NAME  TEXT_TABLE.NAME%TYPE;
BEGIN
  --打开游标,执行查询
  OPEN emp_cursor;
  --提取数据  
  LOOP
       FETCH emp_cursor INTO V_ID,V_NAME;
       IF V_ID<3 THEN
          UPDATE TEXT_TABLE SET NAME = NAME||'1' WHERE ID = V_ID;
       ELSE
          UPDATE TEXT_TABLE SET NAME = NAME||'3' WHERE ID = V_ID;
       END IF;
       EXIT WHEN emp_cursor%NOTFOUND;           
  END LOOP;
  COMMIT;
  --关闭游标
  CLOSE emp_cursor;
END;

2)按逻辑,分别修改参数--FOR

-- 用游标FOR循环的方式实现
DECLARE
  CURSOR emp_cursor IS SELECT ID,NAME from TEXT_TABLE ;
BEGIN
  FOR EMP IN emp_cursor  LOOP      
       IF EMP.ID<3 THEN
          UPDATE TEXT_TABLE SET NAME = NAME||'1' WHERE ID = EMP.ID;
       ELSE
          UPDATE TEXT_TABLE SET NAME = NAME||'3' WHERE ID = EMP.ID;
       END IF;        
  END LOOP;
  COMMIT;
END;

 

3)定义游标时利用FOR UPDATE 子句可以将游标提取出来的数据进行行级锁定

DECLARE
  CURSOR emp_cursor IS SELECT ID,NAME from TEXT_TABLE FOR UPDATE;
BEGIN
  FOR EMP IN emp_cursor  LOOP      
       IF EMP.ID<3 THEN
          UPDATE TEXT_TABLE SET NAME = NAME||'1' WHERE ID = EMP.ID;
       ELSE
          UPDATE TEXT_TABLE SET NAME = NAME||'3' WHERE ID = EMP.ID;
       END IF;        
  END LOOP;
  COMMIT;
END;

 

4)使用NOWAIT

在jin用户下执行修改操作 
 update  TEXT_TABLE set name='1'  where id ='1';

在sys用户执行NOWAIT操作
--FOR UPDATE NOWAIT 不等待锁,如发现所操作的数据行已经锁定,将不会等待,立即返回
DECLARE
  --定义游标
  CURSOR emp_cursor IS SELECT ID,NAME FROM TEXT_TABLE FOR UPDATE NOWAIT; 
BEGIN
  FOR emp IN emp_cursor LOOP    
      DBMS_OUTPUT.put_line(emp.ID||'----'||emp.NAME);      
      IF EMP.ID<3 THEN
          UPDATE TEXT_TABLE SET NAME = NAME||'1' WHERE ID = EMP.ID;
       ELSE
          UPDATE TEXT_TABLE SET NAME = NAME||'3' WHERE ID = EMP.ID;
       END IF;        
  END LOOP;
  COMMIT;
END;

 

效果

ORACLE - <一战通> - 游标_第1张图片

 

5)使用OF字句在特定表上加共享锁(带有参数的游标)

 

--使用OF子句在特定表上加行共享锁 
DECLARE
       CURSOR emp_cursor2 IS
              SELECT TT.ID,TT.NAME,TTL.OPERATE_TYPE,TTL.OPERATE_DATE
              FROM TEXT_TABLE TT join TEXT_TABLE_LOG TTL on TT.ID = TTL.OPERATE_ID
              WHERE TT.ID = &ID
              FOR UPDATE OF TT.ID;
BEGIN
        FOR emp2 IN emp_cursor2 LOOP
            DBMS_OUTPUT.PUT_LINE('ID:'||emp2.ID||'  操作:'||emp2.OPERATE_TYPE||'  操作时间:'||emp2.OPERATE_DATE);
            DELETE FROM TEXT_TABLE WHERE CURRENT OF emp_cursor2;
        END LOOP;
        COMMIT;
END;

 

效果

在sys用户下执行修改操作

 update  JIN.TEXT_TABLE set name='1'  where id ='1';

ORACLE - <一战通> - 游标_第2张图片

 

在jin用户下执行游标操作

ORACLE - <一战通> - 游标_第3张图片

 

在sys用户下执行提交操作,jin用户下锁定的操作随之执行

ORACLE - <一战通> - 游标_第4张图片

 

 

 

 

你可能感兴趣的:(oracle)