`
stone_1231
  • 浏览: 39416 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

plsql游标详解——游标中带参数和参数游标不是一回事

阅读更多
刚打开游标的时候,是位于一个空行,要用fetch into 才能到第一行。

只是要注意用更新游标的时候,不能在游标期间commit. 否则会报
ORA-01002: fetch out of sequence
      就是COMMIT;导致错误
       在打开有for update的cursor时,系统会给取出的数据加上排他锁(exclusive),
       这样在这个锁释放前其他用户不能对这些记录作update、delete和加锁。
       而我一旦执行了commit,锁就释放了,游标也变成无效的,再去fetch数据时就出现错误了。
       因而要把commit放在循环外,等到所有数据处理完成后再commit,然后关闭cursor

隐含游标
--------
又名SQL游标,用于处理单行select into 和 DML语句。
SQL%ISOPEN SQL%FOUND SQL%NOTFOUND SQL%ROWCOUNT

显示游标
--------
用户处理select语句返回的多行数据。
select语句返回多行数据处理方式:[1]显示游标;[2]select ... bulk collect into 集合变量...;

【1】显示游标属性

[1] %ISOPEN 检测游标是否打开。
[2] %FOUND 检测游标结果集是否存在数据。
[3] %NOTFOUND 是否不存在数据。
[4] %ROWCOUNT 游标已提取的实际行数。

【2】使用显示游标

[1] 定义游标

CURSOR cursor_name IS select_statement;

[2] 打开游标

OPEN cursor_name;

[3] 提取数据

FECTH cursor_name INTO variable,...;

[4] 关闭数据

CLOSE cursor_name;

使用标量变量:
-------------
DECLARE
Cursor emp_cur IS select ename,sal from emp order by empno;
v_ename emp.ename%TYPE;
v_sal   emp.sal%TYPE;
BEGIN
IF NOT emp_cur%ISOPEN THEN
   OPEN emp_cur;
   DBMS_OUTPUT.PUT_LINE('打开游标');
END IF;
NULL;
LOOP
   FETCH emp_cur INTO v_ename,v_sal;
   EXIT WHEN emp_cur%NOTFOUND;
   DBMS_OUTPUT.PUT_LINE('用户名:'||v_ename||',工资:'||v_sal);
END LOOP;
NULL;
IF emp_cur%ISOPEN THEN
   CLOSE emp_cur;
   DBMS_OUTPUT.PUT_LINE('关闭游标');
END IF;
END;

使用PLSQL记录变量
-----------------

DECLARE
Cursor emp_cur IS select ename,sal from emp order by empno;
emp_record emp_cur%ROWTYPE;
BEGIN
IF NOT emp_cur%ISOPEN THEN
   OPEN emp_cur;
   DBMS_OUTPUT.PUT_LINE('打开游标');
END IF;
NULL;
LOOP
   FETCH emp_cur INTO emp_record;
   EXIT WHEN emp_cur%NOTFOUND;
   DBMS_OUTPUT.PUT_LINE('用户名:'||emp_record.ename||',工资:'||emp_record.sal);
END LOOP;
NULL;
IF emp_cur%ISOPEN THEN
   CLOSE emp_cur;
   DBMS_OUTPUT.PUT_LINE('关闭游标');
END IF;
END;

使用PLSQL集合变量
-----------------
DECLARE
Cursor emp_cur IS select ename,sal from emp order by empno;
TYPE emp_table_type IS TABLE OF emp_cur%ROWTYPE INDEX BY BINARY_INTEGER;
emp_table emp_table_type;
i number;
BEGIN
i := 1;
IF NOT emp_cur%ISOPEN THEN
   OPEN emp_cur;
   DBMS_OUTPUT.PUT_LINE('打开游标');
END IF;
NULL;
LOOP
   FETCH emp_cur INTO emp_table(i);
   EXIT WHEN emp_cur%NOTFOUND;
   DBMS_OUTPUT.PUT_LINE('用户名:'||emp_table(i).ename||',工资:'||emp_table(i).sal);
   i := i + 1;
END LOOP;
NULL;
IF emp_cur%ISOPEN THEN
   CLOSE emp_cur;
   DBMS_OUTPUT.PUT_LINE('关闭游标');
END IF;
END;

【3】循环游标

FOR record_name IN cursor_name|select_statement LOOP
   statement;
   ....
END LOOP;

使用循环游标
------------
declare
cursor emp_cusor is select ename,sal from emp where deptno = &no order by empno;
begin
for emp_record in emp_cusor loop
      dbms_output.put_line('姓名:'||emp_record.ename||',工资:'||emp_record.sal);
end loop;
end;

begin
for emp_record in (select ename,sal from scott.emp where deptno = &no order by empno) loop
      dbms_output.put_line('姓名:'||emp_record.ename||',工资:'||emp_record.sal);
end loop;
end;

【4】参数游标

CURSOR cursor_name(parameter_name datatype) IS select_statement; --只能制定类型,不能指定具体大小
OPEN cursor_name(参数值);
FECTH cursor_name INTO variable,...;
CLOSE cursor_name;

使用游标参数
------------

示例1:
------
declare
cursor emp_cursor(v_depnto number) is select ename,sal from scott.emp where deptno = v_depnto order by empno;
emp_record emp_cursor%rowtype;
v_dno number;
begin
v_dno := &no;
if not emp_cursor%isopen then
      open emp_cursor(v_dno);
end if;
null;
loop
        fetch emp_cursor into emp_record;
        exit when emp_cursor%notfound;
        dbms_output.put_line('姓名:'||emp_record.ename||',工资:'||emp_record.sal);
end loop;
null;
if emp_cursor%isopen then
       close emp_cursor;
end if;
end;

示例2
-----
declare
cursor emp_cursor(v_depnto number) is select ename,sal from scott.emp where deptno = v_depnto order by empno;
v_dno number;
begin
v_dno := &no;
for emp_record in emp_cursor(v_dno) loop
      dbms_output.put_line('姓名:'||emp_record.ename||',工资:'||emp_record.sal);
end loop;
end;

【5】更新、删除游标行

CURSOR cursor_name IS select_statement
FOR UPDATE [OF column_reference] [NOWAITE];   -- OF子句指定对特定表加锁。
UPDATE table_name SET column=.. WHERE CURRENT OF cursor_name;
DELETE table_name WHERE CURRENT OF cursor_name;


使用游标更新数据
----------------
declare
       cursor test_cursor is select empno,ename,sal,deptno from scott.test for update;
       test_record test_cursor%rowtype;
       v_deptno number;
       v_sal test.sal%type;
begin
       v_deptno := &no;
       if not test_cursor%isopen then
          open test_cursor;
       end if;
       loop
          fetch test_cursor into test_record;
          exit when test_cursor%notfound;
          dbms_output.put_line('姓名:'||test_record.ename||',旧工资:'||test_record.sal);
          if test_record.deptno = v_deptno then
             update scott.test set sal=2*sal where current of test_cursor;
          else
             update scott.test set sal=3*sal where current of test_cursor;
          end if;
       end loop;
       close test_cursor;
end;
      
declare
cursor test_cursor is select empno,ename,sal,deptno from scott.test for update;
      v_deptno NUMBER:=&dno;
begin
for test_record in test_cursor loop
        if test_record.deptno = v_deptno then
                 dbms_output.put_line('姓名:'||test_record.ename||',旧工资:'||test_record.sal);
                 update scott.test set sal = sal*1.5 where current of test_cursor;
           end if;
       end loop;
end;

表test换成emp出现ORA-01410: 无效的 ROWID错误,什么原因???

使用游标删除数据
----------------
declare
cursor test_cursor(v_deptno number) is select deptno,empno,ename,comm from scott.test where deptno = v_deptno for update;
v_dno test.deptno%type := &dno;
begin
     for test_record in test_cursor(v_dno) loop
         if test_record.comm is null then
            dbms_output.put_line('用户名:'||test_record.ename||'部门:'||test_record.deptno);
            delete from scott.test where current of test_cursor;
         end if;
     end loop;    
end;


【6】游标变量

指向内存地址的指针。可以在打开游标时指定其所对应的SELECT语句,实现动态游标。

[1]定义REF CURSOR类型和游标变量:
Type ref_type_name IS REF CURSOR [RETURN return_type --必须是PL/SQL记录类型];
说明:如果指定RETURN子句,那么在打开游标时SELECT语句的返回结果必须与RETURN子句所指定的记录类型匹配。
cursor_variable ref_type name;

SYS_REFCURSOR

[2]打开游标,指定对应的SELECT语句:
OPEN cursor_variable FOR select_statement;
[3]提取数据
FETCH cursor_variable INTO variable1,variable,...;
[4]关闭游标
CLOSE cursor_variable;

不使用RETURN子句
----------------
DECLARE
TYPE ref_type_table IS REF CURSOR;
v_cursor            ref_type_table;
emp_record          emp%rowtype;
BEGIN
     OPEN v_cursor FOR select * from emp where deptno=&no;
     LOOP
         FETCH v_cursor INTO emp_record;
         EXIT WHEN v_cursor%NOTFOUND;
         dbms_output.put_line('员工号:'||emp_record.ename||'部门号:'||emp_record.deptno);
     END LOOP;
     CLOSE v_cursor;
END;

使用RETURN子句
--------------
DECLARE
emp_record          emp%rowtype;
TYPE ref_type_table IS REF CURSOR RETURN emp%rowtype;
v_cursor            ref_type_table;
BEGIN
     OPEN v_cursor FOR select * from emp where deptno=&no;
     LOOP
         FETCH v_cursor INTO emp_record;
         EXIT WHEN v_cursor%NOTFOUND;
         dbms_output.put_line('员工号:'||emp_record.ename||'部门号:'||emp_record.deptno);
     END LOOP;
     CLOSE v_cursor;
END;

DECLARE
Type emp_record_type IS RECORD(
       ename emp.ename%TYPE,
       salary emp.sal%TYPE,
       deptno emp.deptno%TYPE);
emp_record emp_record_type;

TYPE ref_type_table IS REF CURSOR RETURN emp_record_type;
v_cursor            ref_type_table;
BEGIN
     OPEN v_cursor FOR select ename,sal,deptno from emp where deptno=&no;
     LOOP
         FETCH v_cursor INTO emp_record;
         EXIT WHEN v_cursor%NOTFOUND;
         dbms_output.put_line('员工号:'||emp_record.ename||',部门号:'||emp_record.deptno||',工资:'||emp_record.salary);
     END LOOP;
     CLOSE v_cursor;
END;

【7】使用游标批量获取

FETCH ... BULK COLLECT INTO ...[LIMIT row_number];

不限制行数
----------
DECLARE
     CURSOR emp_cursor(v_deptno number) IS SELECT * FROM EMP WHERE deptno = v_deptno;
     TYPE type_emp_table IS TABLE OF emp%ROWTYPE INDEX BY BINARY_INTEGER;
     emp_table type_emp_table;
     v_dno emp.deptno%TYPE;
BEGIN
     v_dno := &no;
     OPEN emp_cursor(v_dno);
     FETCH emp_cursor BULK COLLECT INTO emp_table;
     CLOSE emp_cursor;
     FOR i IN 1..emp_table.COUNT LOOP
         dbms_output.put_line('员工号:'||emp_table(i).ename||'工资:'||emp_table(i).sal);
     END LOOP;
     CLOSE emp_cursor;
END;

限制行数
--------
DECLARE
     CURSOR emp_cursor(v_deptno number) IS SELECT * FROM EMP WHERE deptno = v_deptno;
     TYPE type_emp_table IS TABLE OF emp%ROWTYPE INDEX BY BINARY_INTEGER;
     emp_table type_emp_table;
     v_dno emp.deptno%TYPE;
BEGIN
     v_dno := &no;
     OPEN emp_cursor(v_dno);
     FETCH emp_cursor BULK COLLECT INTO emp_table LIMIT &2;
     CLOSE emp_cursor;
     FOR i IN 1..emp_table.COUNT LOOP
         dbms_output.put_line('员工号:'||emp_table(i).ename||'工资:'||emp_table(i).sal);
     END LOOP;
     CLOSE emp_cursor;
END;

【8】使用CURSOR表达式

作用嵌套游标。

DECLARE
       CURSOR dept_emp_cursor(v_deptno number) IS
   SELECT dname,cursor(SELECT * FROM emp e WHERE e.deptno = d.deptno)
   FROM dept d WHERE deptno = v_deptno;
       TYPE emp_cursor_type IS REF CURSOR;
       emp_cursor emp_cursor_type;
       emp_record emp%ROWTYPE;
       v_name dept.dname%TYPE;
       v_dno emp.deptno%TYPE;
BEGIN
     v_dno := &no;
     OPEN dept_emp_cursor(v_dno);
     loop
          FETCH dept_emp_cursor INTO v_name,emp_cursor;
          EXIT WHEN dept_emp_cursor%NOTFOUND;
          dbms_output.put_line('部门名称:'||v_name);
          LOOP
              FETCH emp_cursor INTO emp_record;           
              EXIT WHEN emp_cursor%NOTFOUND;
              dbms_output.put_line('员工名称:'||emp_record.ename||',工资:'||emp_record.sal);
          END LOOP;
     end loop;
     CLOSE dept_emp_cursor;
END;



转自:http://hi.baidu.com/tangwei%5Fbd/blog/item/f4adbe02e578391b738b6533.html
分享到:
评论

相关推荐

    Oracle PLSQL游标的学习

    游标 for 循环是一种快捷使用游标的方式,它使用 for 循环依次读取结果集中的行数据,当 for 循环开始时,游标自动打开,不需要 open 语句,每循环一次系统自动读取游标当前行的数据,不需要 fetch 语句,当退出 for...

    plsql基础(游标)

    本文将详细介绍游标的概念、基本语法,并通过具体示例讲解如何在不同的循环结构(如`WHILE`、`IF`和`FOR`循环)中使用游标。 #### 二、游标的基本概念 游标是PL/SQL中用于存储SELECT语句结果集的一种机制。它允许...

    PLSQL游标编程培训内含实例

    在"PLSQL培训内容"这个压缩包中,可能包含了关于PLSQL游标编程的PPT资料和相关实例。这些资料将帮助学习者深入理解游标的使用方法和应用场景,通过实例练习进一步巩固知识。建议按照PPT的讲解逐步学习,动手实践每个...

    plsql游标、集合简单使用

    oracle数据库里plsql游标、集合及对象的简单使用,适合初学者查看

    plsql 游标 英文讲义

    显式游标同样支持带有参数的游标,允许程序员在声明时定义参数,以便在运行时向游标传递不同的值。 理解显式游标和隐式游标之间的区别是非常重要的。通过显式游标,程序员可以有更精细的控制数据库查询操作,并且...

    Oracle_PLSQL游标的学习

    游标是 Oracle PL/SQL 中的一个重要概念,它允许用户访问和操作结果集中的数据。游标可以理解为是一个映射在结果集中的一行数据上的位置实体,有了游标,用户就可以访问结果集中的任意一行数据了。 游标的分类: *...

    学习及练习PLSQL-游标遍历

    游标提供了一种对从表中检索出的数据进行操作的灵活手段,就本质而言,游标实际上是一种能从包括多条数据记录的结果集中每次提取一条记录的机制。

    数据库实例详解——图书管理系统(包括SQL代码,游标,存储过程)

    数据库实例详解——图书管理系统 在IT领域,数据库是管理和存储数据的核心工具,尤其在图书管理系统中,数据库的设计和实现显得尤为重要。本实例将深入探讨如何构建一个完整的图书管理系统,涉及的关键知识点包括...

    Oralce PLSQL存储过程之游标实践!

    通过以上实例,我们了解了在PL/SQL存储过程中使用游标的多种方式,包括简单的单值输出、遍历游标、带参数的游标以及使用多个游标进行复杂的数据处理。掌握这些技术将有助于开发出更加高效和健壮的应用程序。

    Oracle数据库实验-PLSQL游标、过程、函数、包的使用[文].pdf

    Oracle数据库是世界上最流行的数据库管理系统之一,它支持一种强大的编程语言——PL/SQL,用于处理数据库中的数据。在本次实验中,我们将重点探讨PL/SQL中的游标、过程、函数和包的使用,这些都是数据库开发中不可或...

    PLSQL 存储过程 游标使用

    PLSQL 存储过程 语法

    超出打开游标的最大数的原因和解决方案

    解决超出打开游标的最大数问题需要从两个方面入手:检查数据库中的 OPEN_CURSORS 参数值和获取打开的游标数。 1. 检查数据库中的 OPEN_CURSORS 参数值 要检查数据库中的 OPEN_CURSORS 参数值,可以使用以下查询: ...

    oracle内部培训资料——游标

    ### Oracle内部培训资料——游标知识点详解 #### 一、游标概述 游标是Oracle数据库中用于处理SQL查询返回的多行记录的一种机制。它允许用户逐行地访问查询结果,这对于处理不确定数量的数据非常有用。游标分为两种...

    福建省电力公司oracle培训教材--PLSQL之游标与异常处理

    福建省电力公司oracle培训教材--PLSQL之游标与异常处理

    PLSQL编程(游标).docx

    在某些情况下,游标可能带有参数,如: ```sql open c_stu('&input_rj'); ``` 这里的`&input_rj`是一个替换变量,实际运行时需要传入具体的值。 4. **提取数据(Fetch Data)** 使用`fetch`语句从游标中获取...

    PLSQL中显示游标使用的4个步骤

    本例简单介绍一下游标处理的4个过程中涉及到的加锁,一致性读的问题.  显式游标处理需四个 PLSQL步骤:  1、定义/声明游标:是定义一个游标名,以及与其相对应的SELECT 语句。  格式:  CURSOR cursor_...

    oracle_plsql_编程详解

    游标是PL/SQL中用于处理查询结果集的一种机制。它可以显式或隐式地打开,读取并关闭结果集。 - **显式游标**:用户定义并控制的游标。 - **隐式游标**:PL/SQL自动创建和管理的游标。 #### 五、异常处理 ##### ...

    Oracle数据库的游标学习总结

    在Oracle数据库中,游标是一种重要的机制,用于处理查询结果集。通过游标,我们可以逐行地读取查询结果,这对于复杂的业务逻辑处理非常有用。本文将详细介绍Oracle数据库中的游标概念、分类及其使用方法,并通过具体...

    Oracle PLSQL语言初级教程之游标

    在PL/SQL中,游标是一种重要的工具,用于处理单行或多行查询结果。本教程主要关注Oracle PL/SQL中的游标及其在数据库访问中的应用。 首先,SQL是用于与Oracle数据库交互的基础语言,而PL/SQL则提供了更多的控制结构...

Global site tag (gtag.js) - Google Analytics