您的当前位置:首页oracle游标用法

oracle游标用法

2023-11-08 来源:哗拓教育

-- 声明游标;CURSOR cursor_name IS select_statement  --For 循环游标 --(1)定义游标 --(2)定义游标变量 --(3)使用for循环来使用这个游标 declare        --类型定义        cursor c_job        is        select empno,ename,job,sal        from emp        where job=‘MANAGER‘;        --定义一个游标变量v_cinfo c_emp%ROWTYPE ,该类型为游标c_emp中的一行数据类型        c_row c_job%rowtype; begin        for c_row in c_job loop          dbms_output.put_line(c_row.empno||‘-‘||c_row.ename||‘-‘||c_row.job||‘-‘||c_row.sal);        end loop; end;          --Fetch游标 --使用的时候必须要明确的打开和关闭  declare        --类型定义        cursor c_job        is        select empno,ename,job,sal        from emp        where job=‘MANAGER‘;        --定义一个游标变量        c_row c_job%rowtype; begin        open c_job;          loop            --提取一行数据到c_row            fetch c_job into c_row;            --判读是否提取到值,没取到值就退出            --取到值c_job%notfound 是false            --取不到值c_job%notfound 是true            exit when c_job%notfound;             dbms_output.put_line(c_row.empno||‘-‘||c_row.ename||‘-‘||c_row.job||‘-‘||c_row.sal);          end loop;        --关闭游标       close c_job; end;  --1:任意执行一个update操作,用隐式游标sql的属性%found,%notfound,%rowcount,%isopen观察update语句的执行情况。        begin          update emp set ENAME=‘ALEARK‘ WHERE EMPNO=7469;          if sql%isopen then            dbms_output.put_line(‘Openging‘);            else              dbms_output.put_line(‘closing‘);              end if;           if sql%found then             dbms_output.put_line(‘游标指向了有效行‘);--判断游标是否指向有效行             else               dbms_output.put_line(‘Sorry‘);               end if;               if sql%notfound then                 dbms_output.put_line(‘Also Sorry‘);                 else                   dbms_output.put_line(‘Haha‘);                   end if;                    dbms_output.put_line(sql%rowcount);                    exception                      when no_data_found then                        dbms_output.put_line(‘Sorry No data‘);                        when too_many_rows then                          dbms_output.put_line(‘Too Many rows‘);                          end; declare        empNumber emp.EMPNO%TYPE;        empName emp.ENAME%TYPE;        begin          if sql%isopen then            dbms_output.put_line(‘Cursor is opinging‘);            else              dbms_output.put_line(‘Cursor is Close‘);              end if;              if sql%notfound then                dbms_output.put_line(‘No Value‘);                else                  dbms_output.put_line(empNumber);                  end if;                  dbms_output.put_line(sql%rowcount);                  dbms_output.put_line(‘-------------‘);                                    select EMPNO,ENAME into  empNumber,empName from emp where EMPNO=7499;                  dbms_output.put_line(sql%rowcount);                                   if sql%isopen then                 dbms_output.put_line(‘Cursor is opinging‘);                 else                 dbms_output.put_line(‘Cursor is Closing‘);                 end if;                  if sql%notfound then                  dbms_output.put_line(‘No Value‘);                  else                  dbms_output.put_line(empNumber);                  end if;                  exception                    when no_data_found then                      dbms_output.put_line(‘No Value‘);                      when too_many_rows then                        dbms_output.put_line(‘too many rows‘);                        end;                                               --2,使用游标和loop循环来显示所有部门的名称 --游标声明 declare        cursor csr_dept        is        --select语句        select DNAME        from Depth;        --指定行指针,这句话应该是指定和csr_dept行类型相同的变量        row_dept csr_dept%rowtype; begin        --for循环        for row_dept in csr_dept loop            dbms_output.put_line(‘部门名称:‘||row_dept.DNAME);        end loop; end;   --3,使用游标和while循环来显示所有部门的的地理位置(用%found属性) declare        --游标声明        cursor csr_TestWhile        is        --select语句        select  LOC        from Depth;        --指定行指针        row_loc csr_TestWhile%rowtype; begin   --打开游标        open csr_TestWhile;        --给第一行喂数据        fetch csr_TestWhile into row_loc;        --测试是否有数据,并执行循环          while csr_TestWhile%found loop            dbms_output.put_line(‘部门地点:‘||row_loc.LOC);            --给下一行喂数据            fetch csr_TestWhile into row_loc;          end loop;        close csr_TestWhile; end; select * from emp            --4,接收用户输入的部门编号,用for循环和游标,打印出此部门的所有雇员的所有信息(使用循环游标) --CURSOR cursor_name[(parameter[,parameter],...)] IS select_statement; --定义参数的语法如下:Parameter_name [IN] data_type[{:=|DEFAULT} value]    declare       CURSOR       c_dept(p_deptNo number)       is       select * from emp where emp.depno=p_deptNo;       r_emp emp%rowtype; begin         for r_emp in c_dept(20) loop             dbms_output.put_line(‘员工号:‘||r_emp.EMPNO||‘员工名:‘||r_emp.ENAME||‘工资:‘||r_emp.SAL);         end loop; end; select * from emp    --5:向游标传递一个工种,显示此工种的所有雇员的所有信息(使用参数游标) declare        cursor        c_job(p_job nvarchar2)        is        select * from emp where JOB=p_job;        r_job emp%rowtype; begin        for r_job in c_job(‘CLERK‘) loop            dbms_output.put_line(‘员工号‘||r_job.EMPNO||‘ ‘||‘员工姓名‘||r_job.ENAME);         end loop; end; SELECT * FROM EMP  --6:用更新游标来为雇员加佣金:(用if实现,创建一个与emp表一摸一样的emp1表,对emp1表进行修改操作),并将更新前后的数据输出出来         create table emp1 as select * from emp;          declare         cursor         csr_Update         is         select * from  emp1 for update OF SAL;         empInfo csr_Update%rowtype;         saleInfo  emp1.SAL%TYPE; begin     FOR empInfo IN csr_Update LOOP       IF empInfo.SAL<1500 THEN         saleInfo:=empInfo.SAL*1.2;        elsif empInfo.SAL<2000 THEN         saleInfo:=empInfo.SAL*1.5;         elsif empInfo.SAL<3000 THEN         saleInfo:=empInfo.SAL*2;       END IF;       UPDATE emp1 SET SAL=saleInfo WHERE CURRENT OF csr_Update;      END LOOP; END;  --7:编写一个PL/SQL程序块,对名字以‘A’或‘S’开始的所有雇员按他们的基本薪水(sal)的10%给他们加薪(对emp1表进行修改操作) declare      cursor       csr_AddSal      is       select * from emp1 where ENAME LIKE ‘A%‘ OR ENAME LIKE ‘S%‘ for update OF SAL;       r_AddSal csr_AddSal%rowtype;       saleInfo  emp1.SAL%TYPE; begin       for r_AddSal in csr_AddSal loop           dbms_output.put_line(r_AddSal.ENAME||‘原来的工资:‘||r_AddSal.SAL);           saleInfo:=r_AddSal.SAL*1.1;           UPDATE emp1 SET SAL=saleInfo WHERE CURRENT OF csr_AddSal;       end loop; end; --8:编写一个PL/SQL程序块,对所有的salesman增加佣金(comm)500 declare       cursor           csr_AddComm(p_job nvarchar2)       is           select * from emp1 where   JOB=p_job FOR UPDATE OF COMM;       r_AddComm  emp1%rowtype;       commInfo emp1.comm%type; begin     for r_AddComm in csr_AddComm(‘SALESMAN‘) LOOP         commInfo:=r_AddComm.COMM+500;          UPDATE EMP1 SET COMM=commInfo where CURRENT OF csr_AddComm;     END LOOP; END;  --9:编写一个PL/SQL程序块,以提升2个资格最老的职员为MANAGER(工作时间越长,资格越老) --(提示:可以定义一个变量作为计数器控制游标只提取两条数据;也可以在声明游标的时候把雇员中资格最老的两个人查出来放到游标中。) declare     cursor crs_testComput     is     select * from emp1 order by HIREDATE asc;     --计数器     top_two number:=2;     r_testComput crs_testComput%rowtype; begin     open crs_testComput;        FETCH crs_testComput INTO r_testComput;           while top_two>0 loop              dbms_output.put_line(‘员工姓名:‘||r_testComput.ENAME||‘ 工作时间:‘||r_testComput.HIREDATE);              --计速器减一              top_two:=top_two-1;              FETCH crs_testComput INTO r_testComput;            end loop;      close crs_testComput; end;       --10:编写一个PL/SQL程序块,对所有雇员按他们的基本薪水(sal)的20%为他们加薪, --如果增加的薪水大于300就取消加薪(对emp1表进行修改操作,并将更新前后的数据输出出来) declare     cursor         crs_UpadateSal     is         select * from emp1 for update of SAL;         r_UpdateSal crs_UpadateSal%rowtype;         salAdd emp1.sal%type;         salInfo emp1.sal%type; begin         for r_UpdateSal in crs_UpadateSal loop            salAdd:= r_UpdateSal.SAL*0.2;            if salAdd>300 then              salInfo:=r_UpdateSal.SAL;               dbms_output.put_line(r_UpdateSal.ENAME||‘:  加薪失败。‘||‘薪水维持在:‘||r_UpdateSal.SAL);              else               salInfo:=r_UpdateSal.SAL+salAdd;               dbms_output.put_line(r_UpdateSal.ENAME||‘:  加薪成功.‘||‘薪水变为:‘||salInfo);            end if;            update emp1 set SAL=salInfo where current of crs_UpadateSal;         end loop; end;       --11:将每位员工工作了多少年零多少月零多少天输出出来    --近似   --CEIL(n)函数:取大于等于数值n的最小整数   --FLOOR(n)函数:取小于等于数值n的最大整数   --truc的用法 http://publish.it168.com/2005/1028/20051028034101.shtml declare   cursor    crs_WorkDay    is    select ENAME,HIREDATE, trunc(months_between(sysdate, hiredate) / 12) AS SPANDYEARS,        trunc(mod(months_between(sysdate, hiredate), 12)) AS months,        trunc(mod(mod(sysdate - hiredate, 365), 12)) as days    from emp1;   r_WorkDay crs_WorkDay%rowtype; begin     for   r_WorkDay in crs_WorkDay loop     dbms_output.put_line(r_WorkDay.ENAME||‘已经工作了‘||r_WorkDay.SPANDYEARS||‘年,零‘||r_WorkDay.months||‘月,零‘||r_WorkDay.days||‘天‘);     end loop; end;   --12:输入部门编号,按照下列加薪比例执行(用CASE实现,创建一个emp1表,修改emp1表的数据),并将更新前后的数据输出出来 --  deptno  raise(%) --  10      5% --  20      10% --  30      15% --  40      20% --  加薪比例以现有的sal为标准 --CASE expr WHEN comparison_expr THEN return_expr --[, WHEN comparison_expr THEN return_expr]... [ELSE else_expr] END declare      cursor          crs_caseTest           is           select * from emp1 for update of SAL;           r_caseTest crs_caseTest%rowtype;           salInfo emp1.sal%type;      begin          for r_caseTest in crs_caseTest loop          case            when r_caseTest.DEPNO=10            THEN salInfo:=r_caseTest.SAL*1.05;            when r_caseTest.DEPNO=20            THEN salInfo:=r_caseTest.SAL*1.1;            when r_caseTest.DEPNO=30            THEN salInfo:=r_caseTest.SAL*1.15;             when r_caseTest.DEPNO=40            THEN salInfo:=r_caseTest.SAL*1.2;          end case;           update emp1 set SAL=salInfo where current of crs_caseTest;         end loop; end;  --13:对每位员工的薪水进行判断,如果该员工薪水高于其所在部门的平均薪水,则将其薪水减50元,输出更新前后的薪水,员工姓名,所在部门编号。 --AVG([distinct|all] expr) over (analytic_clause) ---作用: --按照analytic_clause中的规则求分组平均值。   --分析函数语法:   --FUNCTION_NAME(<argument>,<argument>...)   --OVER   --(<Partition-Clause><Order-by-Clause><Windowing Clause>)      --PARTITION子句      --按照表达式分区(就是分组),如果省略了分区子句,则全部的结果集被看作是一个单一的组      select * from emp1 DECLARE      CURSOR      crs_testAvg      IS      select EMPNO,ENAME,JOB,SAL,DEPNO,AVG(SAL) OVER (PARTITION BY DEPNO ) AS DEP_AVG      FROM EMP1 for update of SAL;      r_testAvg crs_testAvg%rowtype;      salInfo emp1.sal%type;      begin      for r_testAvg in crs_testAvg loop      if r_testAvg.SAL>r_testAvg.DEP_AVG then      salInfo:=r_testAvg.SAL-50;      end if;      update emp1 set SAL=salInfo where current of crs_testAvg;      end loop; end;

oracle游标用法

标签:

小编还为您整理了以下内容,可能对您也有帮助:

oracle中游标的作用有哪些?什么情况下使用?

存储过程中查询语句如何返回多行结果?我们知道,如果存储过程中查询语句有多行结果输出,会报错。若想让存储过程中的查询语句返回多行结果不报错,则需要使用游标来实现。本例主要也是用来熟悉存储过程中游标的简单使用方法:

SET SERVEROUTPUT ON;

create or replace procere proc_salary is

 

--定义变量

 

v_empno emp.empno%TYPE;

v_ename emp.ename%TYPE;

 

v_sal emp.sal%TYPE;  

 

--定义游标 

CURSOR emp_cursor IS  SELECT empno, ename, sal from emp;

BEGIN--循环开始

LOOP

 IF NOT emp_cursor%ISOPEN  THEN

   

OPEN emp_cursor;  END IF;

  

FETCH emp_cursor INTO  v_empno, v_ename, v_sal;

--退出循环的条件 

EXIT WHEN emp_cursor%NOTFOUND OR emp_cursor%NOTFOUND IS NULL;

dbms_output.put_line('员工编号为' || v_empno || '的' || v_ename || '薪水为:' || v_sal);   

END LOOP;END; 

/

游标是什么?ORACLE是怎样使用游标的?举例说明!

游标是什么

游标字面理解就是游动的光标。

用数据库语言来描述:游标是映射在结果集中一行数据上的位置实体,有了游标,用户就可以访问结果集中的任意一行数据了,将游标放置到某行后,即可对该行数据进行操作,例如提取当前行的数据等。

游标的分类

显式游标和隐式游标

显式游标的使用需要4步:

1.

声明游标

CURSOR

mycur(vartype

number)

is

select

emp_no,emp_zc

from

cus_emp_basic

where

com_no

=

vartype;

2.

打开游标

open

mycur(000627)

注:000627是参数

3.

读取数据

fetch

mycur

into

varno,

varprice;

4.

关闭游标

close

mycur;

游标的属性

oracle

游标有4个属性:%ISOPEN,%FOUND,%NOTFOUND,%ROWCOUNT。

%ISOPEN判断游标是否被打开,如果打开%ISOPEN等于true,否则等于false;

%FOUND

%NOTFOUND判断游标所在的行是否有效,如果有效,则%FOUNDD等于true,否则等于false;

%ROWCOUNT返回当前位置为止游标读取的记录行数。

示例

set

serveroutput

on;

declare

varno

varchar2(20);

varprice

varchar2(20);

CURSOR

mycur(vartype

number)

is

select

emp_no,emp_zc

from

cus_emp_basic

where

com_no

=

vartype;

begin

if

mycur%isopen

=

false

then

open

mycur(000627);

end

if;

fetch

mycur

into

varno,varprice;

while

mycur%found

loop

dbms_output.put_line(varno||','||varprice);

if

mycur%rowcount=2

then

exit;

end

if;

fetch

mycur

into

varno,varprice;

end

loop;

close

mycur;

end;

PL/SQL记录的结构和C语言中的结构体类似,是由一组数据项构成的逻辑单元。

PL/SQL记录并不保存在数据库中,它与变量一样,保存在内存空间中,在使用记录时候,要首先定义记录结构,然后声明记录变量。可以把PL/SQL记录看作是一个用户自定义的数据类型。

set

serveroutput

on;

declare

type

person

is

record

(

empno

cus_emp_basic.emp_no%type,

empzc

cus_emp_basic.emp_zc%type);

person1

person;

cursor

mycur(vartype

number)is

select

emp_no,emp_zc

from

cus_emp_basic

where

com_no=vartype;

begin

if

mycur%isopen

=

false

then

open

mycur(000627);

end

if;

loop

fetch

mycur

into

person1;

exit

when

mycur%notfound;

dbms_output.put_line('雇员编号:'||person1.empno||',地址:'||person1.empzc);

end

loop;

close

mycur;

end;

典型游标for

循环

游标for循环示显示游标的一种快捷使用方式,它使用for循环依次读取结果集中的行数据,当form循环开始时,游标自动打开(不需要open),每循环一次系统自动读取游标当前行的数据(不需要fetch),当退出for循环时,游标被自动关闭(不需要使用close)。使用游标for循环的时候不能使用open语句,fetch语句和close语句,否则会产生错误。

set

serveroutput

on;

declare

cursor

mycur(vartype

number)is

select

emp_no,emp_zc

from

cus_emp_basic

where

com_no=vartype;

begin

for

person

in

mycur(000627)

loop

dbms_output.put_line('雇员编号:'||person.emp_no||',地址:'||person.emp_zc);

end

loop;

end;

快速掌握Oracle数据库游标的使用方法

   显式游标

  当查询返回结果超过一行时 就需要一个显式游标 此时用户不能使用select into语句 PL/SQL管理隐式游标 当查询开始时隐式游标打开 查询结束时隐式游标自动关闭 显式游标在PL/SQL块的声明部分声明 在执行部分或异常处理部分打开 取出数据 关闭

  

   使用游标

  这里要做一个声明 我们所说的游标通常是指显式游标 因此从现在起没有特别指明的情况 我们所说的游标都是指显式游标 要在程序中使用游标 必须首先声明游标

  

   声明游标

  语法

  

  CURSOR cursor_name IS select_statement;

  在PL/SQL中游标名是一个未声明变量 不能给游标名赋值或用于表达式中

  

  例

  

  DELCARE CURSOR C_EMP IS SELECT empno ename salary FROM emp WHERE salary> ORDER BY ename; BEGIN

  在游标定义中SELECT语句中不一定非要表可以是视图 也可以从多个表或视图中选择的列 甚至可以使用*来选择所有的列

   打开游标

  使用游标中的值之前应该首先打开游标 打开游标初始化查询处理 打开游标的语法是

  

  OPEN cursor_name

  cursor_name是在声明部分定义的游标名

  

  例

  OPEN C_EMP; 关闭游标

  语法

  CLOSE cursor_name

  

  例

  CLOSE C_EMP; 从游标提取数据 从游标得到一行数据使用FETCH命令 每一次提取数据后 游标都指向结果集的下一行 语法如下

  FETCH cursor_name INTO variable[ variable ]

  对于SELECT定义的游标的每一列 FETCH变量列表都应该有一个变量与之相对应 变量的类型也要相同

  

  

  

  例

  

  SET SERVERIUTPUT ON DECLARE v_ename EMP ENAME%TYPE; v_salary EMP SALARY%TYPE; CURSOR c_emp IS SELECT ename salary FROM emp; BEGIN OPEN c_emp; FETCH c_emp INTO v_ename v_salary; DBMS_OUTPUT PUT_LINE( Salary of Employee || v_ename || is || v_salary); FETCH c_emp INTO v_ename v_salary; DBMS_OUTPUT PUT_LINE( Salary of Employee || v_ename || is || v_salary); FETCH c_emp INTO v_ename v_salary; DBMS_OUTPUT PUT_LINE( Salary of Employee || v_ename || is || v_salary); CLOSE c_emp; END

  这段代码无疑是非常麻烦的 如果有多行返回结果 可以使用循环并用游标属性为结束循环的条件 以这种方式提取数据 程序的可读性和简洁性都大为提高 下面我们使用循环重新写上面的程序

  

  SET SERVERIUTPUT ON DECLARE v_ename EMP ENAME%TYPE; v_salary EMP SALARY%TYPE; CURSOR c_emp IS SELECT ename salary FROM emp; BEGIN OPEN c_emp; LOOP FETCH c_emp INTO v_ename v_salary; EXIT WHEN c_emp%NOTFOUND; DBMS_OUTPUT PUT_LINE( Salary of Employee || v_ename || is || v_salary); END

    

   记录变量

  定义一个记录变量使用TYPE命令和%ROWTYPE 关于%ROWsTYPE的更多信息请参阅相关资料

  记录变量用于从游标中提取数据行 当游标选择很多列的时候 那么使用记录比为每列声明一个变量要方便得多

  当在表上使用%ROWTYPE并将从游标中取出的值放入记录中时 如果要选择表中所有列 那么在SELECT子句中使用*比将所有列名列出来要得多

  例

  

  SET SERVERIUTPUT ON DECLARE R_emp EMP%ROWTYPE; CURSOR c_emp IS SELECT * FROM emp; BEGIN OPEN c_emp; LOOP FETCH c_emp INTO r_emp; EXIT WHEN c_emp%NOTFOUND; DBMS_OUT PUT PUT_LINE( Salary of Employee ||r_emp ename|| is || r_emp salary); END LOOP; CLOSE c_emp; END;

  %ROWTYPE也可以用游标名来定义 这样的话就必须要首先声明游标

  

  SET SERVERIUTPUT ON DECLARE CURSOR c_emp IS SELECT ename salary FROM emp; R_emp c_emp%ROWTYPE; BEGIN OPEN c_emp; LOOP FETCH c_emp INTO r_emp; EXIT WHEN c_emp%NOTFOUND; DBMS_OUT PUT PUT_LINE( Salary of Employee ||r_emp ename|| is || r_emp salary); END LOOP; CLOSE c_emp; END;

   带参数的游标

  与存储过程和函数相似 可以将参数传递给游标并在查询中使用 这对于处理在某种条件下打开游标的情况非常有用 它的语法如下

  

  CURSOR cursor_name[(parameter[ parameter] )] IS select_statement;

  定义参数的语法如下

  

  Parameter_name [IN] data_type[{:=|DEFAULT} value]

  与存储过程不同的是 游标只能接受传递的值 而不能返回值 参数只定义数据类型 没有大小

  另外可以给参数设定一个缺省值 当没有参数值传递给游标时 就使用缺省值 游标中定义的参数只是一个占位符 在别处引用该参数不一定可靠

  在打开游标时给参数赋值 语法如下

  

  OPEN cursor_name[value[ value] ];

  参数值可以是文字或变量

  例

  

  DECALRE CURSOR c_dept IS SELECT * FROM dept ORDER BY deptno; CURSOR c_emp (p_dept VARACHAR ) IS SELECT ename salary FROM emp WHERE deptno=p_dept ORDER BY ename r_dept DEPT%ROWTYPE; v_ename EMP ENAME%TYPE; v_salary EMP SALARY%TYPE; v_tot_salary EMP SALARY%TYPE; BEGIN OPEN c_dept; LOOP FETCH c_dept INTO r_dept; EXIT WHEN c_dept%NOTFOUND; DBMS_OUTPUT PUT_LINE ( Department: || r_dept deptno|| ||r_dept dname); v_tot_salary:= ; OPEN c_emp(r_dept deptno); LOOP FETCH c_emp INTO v_ename v_salary; EXIT WHEN c_emp%NOTFOUND; DBMS_OUTPUT PUT_LINE ( Name: || v_ename|| salary: ||v_salary); v_tot_salary:=v_tot_salary+v_salary; END LOOP; CLOSE c_emp; DBMS_OUTPUT PUT_LINE ( Toltal Salary for dept: || v_tot_salary); END LOOP; CLOSE c_dept; END;

    

   游标FOR循环

  在大多数时候我们在设计程序的时候都遵循下面的步骤

   打开游标

   开始循环

   从游标中取值

   那一行被返回

   处理

   关闭循环

   关闭游标

  可以简单的把这一类代码称为游标用于循环 但还有一种循环与这种类型不相同 这就是FOR循环 用于FOR循环的游标按照正常的声明方式声明 它的优点在于不需要显式的打开 关闭 取数据 测试数据的存在 定义存放数据的变量等等 游标FOR循环的语法如下

  

  FOR record_name IN (corsor_name[(parameter[ parameter] )] | (query_difinition) LOOP statements END LOOP;

  下面我们用for循环重写上面的例子

  

  DECALRE CURSOR c_dept IS SELECT deptno dname FROM dept ORDER BY deptno; CURSOR c_emp (p_dept VARACHAR ) IS SELECT ename salary FROM emp WHERE deptno=p_dept ORDER BY ename v_tot_salary EMP SALARY%TYPE; BEGIN FOR r_dept IN c_dept LOOP DBMS_OUTPUT PUT_LINE ( Department: || r_dept deptno|| ||r_dept dname); v_tot_salary:= ; FOR r_emp IN c_emp(r_dept deptno) LOOP DBMS_OUTPUT PUT_LINE ( Name: || v_ename || salary: || v_salary); v_tot_salary:=v_tot_salary+v_salary; END LOOP; DBMS_OUTPUT PUT_LINE ( Toltal Salary for dept: || v_tot_salary); END LOOP; END;

   在游标FOR循环中使用查询

  在游标FOR循环中可以定义查询 由于没有显式声明所以游标没有名字 记录名通过游标查询来定义

  

  DECALRE v_tot_salary EMP SALARY%TYPE; BEGIN FOR r_dept IN (SELECT deptno dname FROM dept ORDER BY deptno) LOOP DBMS_OUTPUT PUT_LINE( Department: || r_dept deptno|| ||r_dept dname); v_tot_salary:= ; FOR r_emp IN (SELECT ename salary    FROM emp    WHERE deptno=p_dept    ORDER BY ename) LOOP DBMS_OUTPUT PUT_LINE( Name: || v_ename|| salary: ||v_salary); v_tot_salary:=v_tot_salary+v_salary; END LOOP; DBMS_OUTPUT PUT_LINE( Toltal Salary for dept: || v_tot_salary); END LOOP; END;

   游标中的子查询

  语法如下

  

  CURSOR C IS SELECT * FROM emp WHERE deptno NOT IN (SELECT deptno FROM dept WHERE dname!= ACCOUNTING );

  可以看出与SQL中的子查询没有什么区别

  

    

   游标中的更新和删除

  在PL/SQL中依然可以使用UPDATE和DELETE语句更新或删除数据行 显式游标只有在需要获得多行数据的情况下使用 PL/SQL提供了仅仅使用游标就可以执行删除或更新记录的方法

  UPDATE或DELETE语句中的WHERE CURRENT OF子串专门处理要执行UPDATE或DELETE操作的表中取出的最近的数据 要使用这个方法 在声明游标时必须使用FOR UPDATE子串 当对话使用FOR UPDATE子串打开一个游标时 所有返回集中的数据行都将处于行级(ROW LEVEL)独占式锁定 其他对象只能查询这些数据行 不能进行UPDATE DELETE或SELECT FOR UPDATE操作

  语法

  

  FOR UPDATE [OF [schema ]lumn[ [schema ]lumn] [nowait]

  在多表查询中 使用OF子句来锁定特定的表 如果忽略了OF子句 那么所有表中选择的数据行都将被锁定 如果这些数据行已经被其他会话锁定 那么正常情况下ORACLE将等待 直到数据行解锁

  在UPDATE和DELETE中使用WHERE CURRENT OF子串的语法如下

  

  WHERE{CURRENT OF cursor_name|search_condition}

  例

  

  DELCARE CURSOR c IS SELECT empno salary FROM emp WHERE m IS NULL FOR UPDATE OF m; v_m NUMBER( ); BEGIN FOR r IN c LOOP IF r salary< THEN v_m:=r salary* ; ELSEIF r salary< THEN v_m:=r salary* ; ELSEIF r salary< THEN v_m:=r salary* ; ELSE v_m:=r salary* ; END IF; UPDATE emp; SET m=v_m WHERE CURRENT OF c l; END LOOP; END

lishixin/Article/program/Oracle/201311/16865

快速掌握Oracle数据库游标的使用方法

   显式游标

  当查询返回结果超过一行时 就需要一个显式游标 此时用户不能使用select into语句 PL/SQL管理隐式游标 当查询开始时隐式游标打开 查询结束时隐式游标自动关闭 显式游标在PL/SQL块的声明部分声明 在执行部分或异常处理部分打开 取出数据 关闭

  

   使用游标

  这里要做一个声明 我们所说的游标通常是指显式游标 因此从现在起没有特别指明的情况 我们所说的游标都是指显式游标 要在程序中使用游标 必须首先声明游标

  

   声明游标

  语法

  

  CURSOR cursor_name IS select_statement;

  在PL/SQL中游标名是一个未声明变量 不能给游标名赋值或用于表达式中

  

  例

  

  DELCARE CURSOR C_EMP IS SELECT empno ename salary FROM emp WHERE salary> ORDER BY ename; BEGIN

  在游标定义中SELECT语句中不一定非要表可以是视图 也可以从多个表或视图中选择的列 甚至可以使用*来选择所有的列

   打开游标

  使用游标中的值之前应该首先打开游标 打开游标初始化查询处理 打开游标的语法是

  

  OPEN cursor_name

  cursor_name是在声明部分定义的游标名

  

  例

  OPEN C_EMP; 关闭游标

  语法

  CLOSE cursor_name

  

  例

  CLOSE C_EMP; 从游标提取数据 从游标得到一行数据使用FETCH命令 每一次提取数据后 游标都指向结果集的下一行 语法如下

  FETCH cursor_name INTO variable[ variable ]

  对于SELECT定义的游标的每一列 FETCH变量列表都应该有一个变量与之相对应 变量的类型也要相同

  

  

  

  例

  

  SET SERVERIUTPUT ON DECLARE v_ename EMP ENAME%TYPE; v_salary EMP SALARY%TYPE; CURSOR c_emp IS SELECT ename salary FROM emp; BEGIN OPEN c_emp; FETCH c_emp INTO v_ename v_salary; DBMS_OUTPUT PUT_LINE( Salary of Employee || v_ename || is || v_salary); FETCH c_emp INTO v_ename v_salary; DBMS_OUTPUT PUT_LINE( Salary of Employee || v_ename || is || v_salary); FETCH c_emp INTO v_ename v_salary; DBMS_OUTPUT PUT_LINE( Salary of Employee || v_ename || is || v_salary); CLOSE c_emp; END

  这段代码无疑是非常麻烦的 如果有多行返回结果 可以使用循环并用游标属性为结束循环的条件 以这种方式提取数据 程序的可读性和简洁性都大为提高 下面我们使用循环重新写上面的程序

  

  SET SERVERIUTPUT ON DECLARE v_ename EMP ENAME%TYPE; v_salary EMP SALARY%TYPE; CURSOR c_emp IS SELECT ename salary FROM emp; BEGIN OPEN c_emp; LOOP FETCH c_emp INTO v_ename v_salary; EXIT WHEN c_emp%NOTFOUND; DBMS_OUTPUT PUT_LINE( Salary of Employee || v_ename || is || v_salary); END

    

   记录变量

  定义一个记录变量使用TYPE命令和%ROWTYPE 关于%ROWsTYPE的更多信息请参阅相关资料

  记录变量用于从游标中提取数据行 当游标选择很多列的时候 那么使用记录比为每列声明一个变量要方便得多

  当在表上使用%ROWTYPE并将从游标中取出的值放入记录中时 如果要选择表中所有列 那么在SELECT子句中使用*比将所有列名列出来要得多

  例

  

  SET SERVERIUTPUT ON DECLARE R_emp EMP%ROWTYPE; CURSOR c_emp IS SELECT * FROM emp; BEGIN OPEN c_emp; LOOP FETCH c_emp INTO r_emp; EXIT WHEN c_emp%NOTFOUND; DBMS_OUT PUT PUT_LINE( Salary of Employee ||r_emp ename|| is || r_emp salary); END LOOP; CLOSE c_emp; END;

  %ROWTYPE也可以用游标名来定义 这样的话就必须要首先声明游标

  

  SET SERVERIUTPUT ON DECLARE CURSOR c_emp IS SELECT ename salary FROM emp; R_emp c_emp%ROWTYPE; BEGIN OPEN c_emp; LOOP FETCH c_emp INTO r_emp; EXIT WHEN c_emp%NOTFOUND; DBMS_OUT PUT PUT_LINE( Salary of Employee ||r_emp ename|| is || r_emp salary); END LOOP; CLOSE c_emp; END;

   带参数的游标

  与存储过程和函数相似 可以将参数传递给游标并在查询中使用 这对于处理在某种条件下打开游标的情况非常有用 它的语法如下

  

  CURSOR cursor_name[(parameter[ parameter] )] IS select_statement;

  定义参数的语法如下

  

  Parameter_name [IN] data_type[{:=|DEFAULT} value]

  与存储过程不同的是 游标只能接受传递的值 而不能返回值 参数只定义数据类型 没有大小

  另外可以给参数设定一个缺省值 当没有参数值传递给游标时 就使用缺省值 游标中定义的参数只是一个占位符 在别处引用该参数不一定可靠

  在打开游标时给参数赋值 语法如下

  

  OPEN cursor_name[value[ value] ];

  参数值可以是文字或变量

  例

  

  DECALRE CURSOR c_dept IS SELECT * FROM dept ORDER BY deptno; CURSOR c_emp (p_dept VARACHAR ) IS SELECT ename salary FROM emp WHERE deptno=p_dept ORDER BY ename r_dept DEPT%ROWTYPE; v_ename EMP ENAME%TYPE; v_salary EMP SALARY%TYPE; v_tot_salary EMP SALARY%TYPE; BEGIN OPEN c_dept; LOOP FETCH c_dept INTO r_dept; EXIT WHEN c_dept%NOTFOUND; DBMS_OUTPUT PUT_LINE ( Department: || r_dept deptno|| ||r_dept dname); v_tot_salary:= ; OPEN c_emp(r_dept deptno); LOOP FETCH c_emp INTO v_ename v_salary; EXIT WHEN c_emp%NOTFOUND; DBMS_OUTPUT PUT_LINE ( Name: || v_ename|| salary: ||v_salary); v_tot_salary:=v_tot_salary+v_salary; END LOOP; CLOSE c_emp; DBMS_OUTPUT PUT_LINE ( Toltal Salary for dept: || v_tot_salary); END LOOP; CLOSE c_dept; END;

    

   游标FOR循环

  在大多数时候我们在设计程序的时候都遵循下面的步骤

   打开游标

   开始循环

   从游标中取值

   那一行被返回

   处理

   关闭循环

   关闭游标

  可以简单的把这一类代码称为游标用于循环 但还有一种循环与这种类型不相同 这就是FOR循环 用于FOR循环的游标按照正常的声明方式声明 它的优点在于不需要显式的打开 关闭 取数据 测试数据的存在 定义存放数据的变量等等 游标FOR循环的语法如下

  

  FOR record_name IN (corsor_name[(parameter[ parameter] )] | (query_difinition) LOOP statements END LOOP;

  下面我们用for循环重写上面的例子

  

  DECALRE CURSOR c_dept IS SELECT deptno dname FROM dept ORDER BY deptno; CURSOR c_emp (p_dept VARACHAR ) IS SELECT ename salary FROM emp WHERE deptno=p_dept ORDER BY ename v_tot_salary EMP SALARY%TYPE; BEGIN FOR r_dept IN c_dept LOOP DBMS_OUTPUT PUT_LINE ( Department: || r_dept deptno|| ||r_dept dname); v_tot_salary:= ; FOR r_emp IN c_emp(r_dept deptno) LOOP DBMS_OUTPUT PUT_LINE ( Name: || v_ename || salary: || v_salary); v_tot_salary:=v_tot_salary+v_salary; END LOOP; DBMS_OUTPUT PUT_LINE ( Toltal Salary for dept: || v_tot_salary); END LOOP; END;

   在游标FOR循环中使用查询

  在游标FOR循环中可以定义查询 由于没有显式声明所以游标没有名字 记录名通过游标查询来定义

  

  DECALRE v_tot_salary EMP SALARY%TYPE; BEGIN FOR r_dept IN (SELECT deptno dname FROM dept ORDER BY deptno) LOOP DBMS_OUTPUT PUT_LINE( Department: || r_dept deptno|| ||r_dept dname); v_tot_salary:= ; FOR r_emp IN (SELECT ename salary    FROM emp    WHERE deptno=p_dept    ORDER BY ename) LOOP DBMS_OUTPUT PUT_LINE( Name: || v_ename|| salary: ||v_salary); v_tot_salary:=v_tot_salary+v_salary; END LOOP; DBMS_OUTPUT PUT_LINE( Toltal Salary for dept: || v_tot_salary); END LOOP; END;

   游标中的子查询

  语法如下

  

  CURSOR C IS SELECT * FROM emp WHERE deptno NOT IN (SELECT deptno FROM dept WHERE dname!= ACCOUNTING );

  可以看出与SQL中的子查询没有什么区别

  

    

   游标中的更新和删除

  在PL/SQL中依然可以使用UPDATE和DELETE语句更新或删除数据行 显式游标只有在需要获得多行数据的情况下使用 PL/SQL提供了仅仅使用游标就可以执行删除或更新记录的方法

  UPDATE或DELETE语句中的WHERE CURRENT OF子串专门处理要执行UPDATE或DELETE操作的表中取出的最近的数据 要使用这个方法 在声明游标时必须使用FOR UPDATE子串 当对话使用FOR UPDATE子串打开一个游标时 所有返回集中的数据行都将处于行级(ROW LEVEL)独占式锁定 其他对象只能查询这些数据行 不能进行UPDATE DELETE或SELECT FOR UPDATE操作

  语法

  

  FOR UPDATE [OF [schema ]lumn[ [schema ]lumn] [nowait]

  在多表查询中 使用OF子句来锁定特定的表 如果忽略了OF子句 那么所有表中选择的数据行都将被锁定 如果这些数据行已经被其他会话锁定 那么正常情况下ORACLE将等待 直到数据行解锁

  在UPDATE和DELETE中使用WHERE CURRENT OF子串的语法如下

  

  WHERE{CURRENT OF cursor_name|search_condition}

  例

  

  DELCARE CURSOR c IS SELECT empno salary FROM emp WHERE m IS NULL FOR UPDATE OF m; v_m NUMBER( ); BEGIN FOR r IN c LOOP IF r salary< THEN v_m:=r salary* ; ELSEIF r salary< THEN v_m:=r salary* ; ELSEIF r salary< THEN v_m:=r salary* ; ELSE v_m:=r salary* ; END IF; UPDATE emp; SET m=v_m WHERE CURRENT OF c l; END LOOP; END

lishixin/Article/program/Oracle/201311/16865

oracle中的游标使用静态游标

  游标是构建在PL/SQL中 用来查询数据 获取记录集的指针 它让开发者 一次访问结果集中一行记录

  在oracle中提供了两种游标 静态游标 ref游标

  静态游标 静态游标是在编译的时候就被确定 然后把结果集复制到内存中 静态游标又分为两种 隐式游标和显示游标

  ref游标 ref游标是在运行的时候加载结果集

  先来看看静态游标中的隐式游标

  在PL/SQL中为所有的SQL数据操纵语句(包括返回一行的select)隐式声明游标 称为隐式游标 主要原因是用户不能直接命名和控制此类游标 当用户在PL/SQL 中使用数据操纵语句(DML)时 oracle预先定义一个名称为SQL的隐式游标 通过 检查隐式游标的属性获取与最近执行的SQL语句相关信息 在执行DML语句之后 隐式游标属性返回信息 隐式游标属性包括 %found %notfound %rowcount %isopen %found 只有DML语句影响一行或多行时 %found属性才返回true declare num number; begin update emp set empno= where empno= ; if sql%found then dbms_output put_line( 存在记录 ); else dbms_output put_line( 不存在记录 ); end if; end; %notfound %notfound属性作用正好跟%found属性相反 如果DML语句没有影响任何行数 则%notfound属性返回true declare begin delete from emp where empno= ; if sql%notfound then dbms_output put_line( 删除失败 ); end if; end; %rowcount %rowcount属性返回DML语句影响的行数 如果DML语句没有影响任何行数 则%rowcount属性将返回 declare num number; begin update emp set empno= where empno= ; if sql%rowcount= then dbms_output put_line( 不存在记录 ); else dbms_output put_line( 存在记录 ); end if; end; %isopen %isopen属性判断SQL游标是否已经打开 在执行SQL语句之后 oracle自动关闭SQL 游标 所以隐式游标的%isopen属性始终为false 在PL/SQL中向标准的select语句增加单独的into子句 就可以将从表或视图中查询的记录赋予变量或行变量 需要注意的是select into 语句结果必须有且只能有一行 如果查询没有返回行 PL/SQL将抛出no_data_found异常 如果查询返回多行 则抛出 too_many_rows 异常 如果抛出异常 则停止执行 控制权转移到异常处理部分(没有 异常处理 则程序中断) 在引发异常时 将不使用属性%found %notfound %rowcount来查明DML语句是否 已影响了行数 declare num number; begin select empno into num from emp where empno= ; if sql%rowcount= or sql%notfound then dbms_output put_line( 不存在记录 ); else dbms_output put_line( 存在记录 ); end if; end;

  

  显示游标 显示游标是由用户显示声明的游标 根据在游标中定义的查询 查询返回的行集合可以 包含零行或多行 这些行称为活动集 游标将指向活动集中的当前行 显示游标的操作过程 使用显示游标的 个步骤 ( )声明游标 ( )打开游标 ( )从游标中获取结果集 ( )关闭游标 cursor cursor_name [(parameter[ parameter])] [return return_type] is select_statement; cursor_name 指游标的名称 parameter   为游标指定输入参数 return_type 定义游标提取行的行类型 select_statement 为游标定义查询语句 open 游标名称 fetch 从游标中提取行 close 关闭游标

   打开游标 执行游标中定义的查询语句 绑定输入参数 将游标指针指 向结果集的BOF位置 open cursor_name [parameters]

      fetch 在打开游标之后 可以从游标中提取记录 fetch cursor_name into variable_name; fetch 是提取结果集中一行记录存储在变量中 每次提取之后 结果集指针 就向前移动一行

   close 在处理游标中的所有行之后 必须关闭游标 以释放分配给游标的所有资源 close cursor_name 用户可以通过检查游标属性来确定游标的当前状态

  显示游标的属性如下 %found 如果执行最后一条fetch语句 成功返回行 则%found属性为true %notfound 如果执行最后一条fetch语句 未能提取行 则%notfound属性为true %isopen:如果游标已经打开 则返回true 否则返回false %rowcount 返回到目前为止游标提取的行数 %rowcount为数字类型属性 在第一 次获取之前 %rowcount为零 当fetch语句返回一行时 则该数加

  declare info emp%rowtype; cursor my_cur is select * from emp where empno= ; begin open my_cur; dbms_output put_line(my_cur%rowcount); loop if my_cur%isopen then fetch my_cur into info; exit when my_cur%notfound; dbms_output put_line(info empno); dbms_output put_line(my_cur%rowcount); end if; end loop; close my_cur; end;

  

  使用显示游标删除或更新 使用游标时 如果处理过程中需要删除或更新 在定义游标查询语句时 必须使用select for update语句 而在执行delete或update时使用 where current of 子句指定游标当前行 cursor cursor_name is select_statement for update[of column] wait/nowait 在使用for update 子句声明游标之后 可以使用以下语法更新行 update table_name set column_name=column_value where current of cursor_name; update命令中使用的列必须出现在for update of 子句中 select 语句必须只包括一个表 而且delete和update语句只有在打开游标并且提取 特定行之后才能使用

  declare cursor cur_emp is select * from emp where sal< for update of sal; num emp%rowtype; begin open cur_emp; loop fetch cur_emp into num; exit when cur_emp%notfound; update emp set sal= where current of cur_emp; end loop; close cur_emp; end;

  

  带参数的显示游标 PL/SQL中允许显示游标接受输入参数 用于声明带参数的显示游标语法 cursor cursor_name[<param_name> data_type] [return <return type>] is select_statement declare dept_num emp deptno%type; emp_num   emp empno%type; emp_nam emp ename%type; cursor emp_cur(deptparam number) is select empno ename from emp where deptno=deptparam; begin dept_num :=&部门编号; open emp_cur(dept_num); loop fetch emp_cur into emp_num emp_nam; exit when emp_cur%notfound; dbms_output put_line(emp_num|| ||emp_nam); end loop; close emp_cur; end;

  可以使用循环游标来简化显示游标

  循环游标隐式打开显示游标(不需要open) 自动从结果集提取记录 然后处理完所有记录自动关闭游标 循环游标自动创建 %rowtype类型的变量并将此变量用做记录的索引 循环游标语法如下 for record_index in cursor_name record_index是PL/SQL自动创建的变量 此变量的属性声明为%rowtype类型 作用 域for循环之内

  循环游标的特性有 从游标中提取所有记录之后自动关闭游标

lishixin/Article/program/Oracle/201311/18322

oracle的游标用法,for循环游标和fetch into用法上有什么区别

在oracle中游标可以使用for来进行循环,也可以使用fetch方式来循环。

游标的for循环是oracle所有的一个便利的游标操作功能,用for游标循环,可以省去打开游标,关闭游标等操作,而将注意力放在游标循环内的处理上;而且可以不定义游标,直接使用一个子查询作为for循环的游标。例如:

for rc in (select field_a, field_b from table_name) loop

-- 循环处理 

end loop;

显示全文