oracle中的游标 包 集合 的学习总结


游标:

   1、cursor_name%ROWCOUNT 表示游标影响了多少行,如:sql%rowcount中的sql是oracle的内部游标,rowcount的意思是之前的dml sql语句影响的多少行数据。如果是delete操作rowcount就是delete的数据,如果是insert,就是插入的数量......

  2、游标的目标变量(v_empno, v_sal)必须与游标select 表中得列的数据类型(就是emp表中的数据类型咯,可以用%emp.empno或者 %emp.sal 这样永远错不了哈哈)一致。

  3、如果试图打开一个已经打开的,或者关闭一个已经关闭的游标都会出现错误,如果不清楚目前游标的状态,那就用一个%isopen 进行检查。

    如下: if mycursor%isopen then

              fetch mycursor into v_empno;

           else

             open mycursor;

           end if;

隐式游标:

 每个隐式游标都有一个 into 

 数据类型一致

 一次只能返回一行否则会报 NO_DATA_FOUND 和 TOO_MANY_ROWS 异常。。可以用 ROWNUM=1来约束一下。

 来个小例子吧。不过真正应用的时候还是显示游标用得多:

     create or replace procedure cx_xm(in_xh  in  char ,out_xm out varcharw)

     as

     begin

         select xm into out_xm from sxb where xh=in_xh and rownum=1;

    dbms_outputl.put_line(out_xm);

   end cx_xm; 

   

任何变量只有当游标打开的时候才能被赋值,下面例子中每一行检索都会乘以2,这个factor的增长不会影响fetch的读取

 DECLARE

my_sal employees.salary%TYPE;

my_job employees.job_id%TYPE;

factor INTEGER := 2;

CURSOR c1 IS

SELECT factor*salary FROM employees WHERE job_id = my_job; --我一直不明白为什么会等于一个变量。。。

BEGIN

OPEN c1; -- factor initially equals 2    

LOOP

FETCH c1 INTO my_sal;

EXIT WHEN c1%NOTFOUND;

factor := factor + 1; -- does not affect FETCH ;这里不影响一个读取,只有factor自己在加。

END LOOP;

CLOSe c1;

END;

因为fetch读取的时候是自动向下移动一行的,所以我们可以用不同的fetch...into 句子分别对同一个cursor操作,可以和循环差不多。。看个例子:

DECLARE
CURSOR c1 IS SELECT last_name FROM employees ORDER BY last_name;
name1 employees.last_name%TYPE;
name2 employees.last_name%TYPE;
name3 employees.last_name%TYPE;
BEGIN
OPEN c1;
FETCH c1 INTO name1; -- this fetches first row注意这里取了第一行
FETCH c1 INTO name2; -- this fetches second row 取了第二行
FETCH c1 INTO name3; -- this fetches third row取了第三行
CLOSE c1;
END;
/

 注意这个fetch操作取到最后一行后也不会提醒,不报错,所以要我们用cursor的属性%found 和 %notfound

   关于%rowcount的属性不必在写了,看个例子一目了然了:

         DECLARE

CURSOR c1 IS SELECT last_name FROM employees WHERE ROWNUM < 11;

name employees.last_name%TYPE;

BEGIN

OPEN c1;

LOOP

FETCH c1 INTO name;

EXIT WHEN c1%NOTFOUND OR c1%NOTFOUND IS NULL;
DBMS_OUTPUT.PUT_LINE(c1%ROWCOUNT || '. ' || name);
IF c1%ROWCOUNT = 5 THEN
DBMS_OUTPUT.PUT_LINE('--- Fetched 5th record ---');
END IF;
END LOOP;
CLOSE c1;
END;
/




 Referencing %FOUND, %NOTFOUND, or %ROWCOUNT before a cursor is opened or
after it is closed raises INVALID_CURSOR.

 After the first FETCH, if the result set was empty, %FOUND yields FALSE,
%NOTFOUND yields TRUE, and %ROWCOUNT yields 0.


游标其实也可以给参数的,这样你就可以在打开游标的时候传递参数值了,如果一个查询经常被用到,你还可以给参数一个默认值,看一个简单的例子

declare

 cursor c1 (job varchar2,max_wage number) is  --亮点在这,给c1两个参数

  select * fron employees where job_id=job and salary>max_wage;--在这用到这俩参数了。

begin

 for person in c1('clerk',3000)--调用游标,赋值。

 loop

  dbms_output.put_line('name='||person.last_name||',salary='|| person.salary||',jobid='||person,job_id);

  end loop

end;

 


Example 6–23 Passing Parameters to Explicit Cursors

DECLARE

emp_job employees.job_id%TYPE := 'ST_CLERK';

emp_salary employees.salary%TYPE := 3000;

my_record employees%ROWTYPE;

CURSOR c1 (job VARCHAR2, max_wage NUMBER) IS

SELECT * FROM employees WHERE job_id = job and salary > max_wage;

BEGIN

-- Any of the following statements opens the cursor:

-- OPEN c1('ST_CLERK', 3000); OPEN c1('ST_CLERK', emp_salary);

-- OPEN c1(emp_job, 3000); OPEN c1(emp_job, emp_salary);

OPEN c1(emp_job, emp_salary);

LOOP

FETCH c1 INTO my_record;

EXIT WHEN c1%NOTFOUND;

-- process data record

DBMS_OUTPUT.PUT_LINE('Name = ' || my_record.last_name || ', salary = ' ||

my_record.salary || ', Job Id = ' || my_record.job_id );

END LOOP;

END

 游标变量:

   注意几个游标变量的约束条件:

  1、不能在包或者包体中声明游标变量,但是定义游标类型是可以的:

CREATE PACKAGE emp_data AS

TYPE EmpCurTyp IS REF CURSOR RETURN employees%ROWTYPE; --定义游标类型是可以的。

-- emp_cv EmpCurTyp; -- not allowed --这个是不允许的,

2、如果你在一个oci客户端绑定了一个游标变量到一个plsql块中,你不能从服务器端读取数据,除非你也在服务器端打开了它。

3、你不能用比较操作测试游标变量是否相等,是否无效。

4、数据库的列不能存储游标变量的值,在创建表的句法中没有等效的类型来用。

5、不能把游标变量存储在组合数组,内嵌表,可变数组中。

6、游标和游标变量是不能彼此协作的,你不能在一个游标的循环中参照一个游标变量。

包:

  串行可再用的包: oracle实例需要一个可用的实例区间,他是在SGA的LRU(least-recently used)池中已经为这个包分配了,也配置好了的,在向服务器调用的结尾,这个区间会归还给LRU池,把LRU池放在SGA中的原因就是这个工作区可以被不同的用户同时使用,可以串行化调用同一个包。

  由于不可串行化包存在于一个会话的整个生命过程中,这就在真个session过程中锁定了UGA内存。

 句法:pragma serially_reusable;

下面看一个例子:

包变量 下面的例子用到了串行复用包声明;

 connect scott/liu1990

  create or replace package Sr_pkg is 

   pragma serially_reusable;

   n  number:=5;

  end Sr_pkg;

再次连接

 connect scott/liu1990

 --第一次访问服务器

 begin

  Sr_pkg.n:=10;

 end;

 --第二次访问服务器

 begin

  dbms_output.put_line(Sr_pkg.n);

 end;

输出结果 5   

 为什么不是10呢?哈哈,这就是serially_reusable的作用了,如果没有这句,那结果才是10哦。

存储程序模块(存储过程,函数,包)

    默认参数值:create or replace procedure get_emp_names(dept_num in numberdefault 20)  is ....

               或者:create or replace procedure get_emp_names(dept_num in number:=20)  is ....

当你调用这个存储过程的时候,如果为其赋值,那默认值将被重写。在这里你不能用declare关键字来定义变量、游标、异常,一用这个就会出错的。


创建包 包体:

  可以包体可以包含如下内容: 过程、函数、游标的声明,本机的过程或者函数,本机的变量。

 例:

 

应用批量绑定:

 declare 

  type numlis is varry(100) of number;

  id numlist := numlist(7902,7698,7839);

begin

 forall i in id.first .. id.last  ---批量绑定可变数组的值,关键字 forall

 update emp set sal = 1.2 * sal where mgr=id(i);


再看一个没有使用批量绑定的块:

 for i in id.first .. id.last 

  loop

     update emp set sal = 1.2*sal where mgr= id(i);

  end loop;

end;


查询,用BULK COLLECT INTO 子句可以显著提高查询性能的:附上一个小例:

 declare

 type var_tab is table of varchar2(20) index by binary_integer; 

--创建一个varchar2类型的表,加上一个binnary_integer类型的索引

 empno var_tab;

 ename var_tab;

 counter number;

 cursor c is select empno , ename  from emp where mgr=7698;

begin

 select empno,ename BULK COLLECT INTO empno, ename from emp where mgr=7698;

 --下面是利用游标实现的

 counter:=1;

 for rec in c 

  loop

   empno(counter) :=rec.empno;

   ename(counter) :=rec.ename;

   counter :=counter+1;

  end loop;

end;


再来一个 用于更新各个员工bonus的例子:

declare

 type emplist is varray(100) of number;

 empids emplist :=emplist(7369,7499,7521,7654,7698);

--与下面的赋值方法比较一下

 type bonliset is table of emp.sal%type;

 bonlist_inst bonlist;

begin

 bonlist_inst :=bonlist(1,2,3,4,5);

--对应上面的赋值方法,注意下。

 forall i in empids.first .. empids.last

 update emp set bonus = 0.1 * sal where empno = empids(i) 

 returning sal BULK COLLECT INTO bonlist;

--下面这种传统的更新,没有用批量绑定,效率低下。

 for i in empids.first .. empids.last loop

 uodate emp set bonus = 0.1 * sal where empno = empids(i)

 returning sal INTO bonlist(i);

 end loop;

end;

 如果没有批量绑定,pl/sql把每个employee的更新发送 sql命令到sql 引擎,很多的上下文切换(context switches)会大大降低了更新效率。

signnatures 和 timestamps:两种远程依赖模式
 remote_dependencies_mode参数有两个值TIMESTAMP 
与 SIGNATURE

当设置为TIMESTAMP时用于指定数据库为远程 PL/SQL 存储的过程处理被依赖对象的方式。如果设置为 TIMESTAMP, 只有在服务器与本地时间戳相匹配的情况下, 才能执行该过程。如果设置为 SIGNATURE,
在签名安全的情况下即可执行该过程。


游标变量的使用实例:

         Examples of Cursor Variables
This section includes several examples of cursor variable usage in PL/SQL. For
additional cursor variable examples that use the programmatic interfaces, refer to the
following manuals:
■ Pro*C/C++ Programmer's Guide
■ Pro*COBOL Programmer's Guide
■ Oracle Call Interface Programmer's Guide
■ Oracle SQL*Module for Ada Programmer's Guide
Fetching Data
The following package defines a PL/SQL cursor variable type Emp_val_cv_type,
and two procedures. The first procedure, Open_emp_cv, opens the cursor variable
using a bind variable in the WHERE clause. The second procedure, Fetch_emp_data,
fetches rows from the Emp_tab table using the cursor variable.

CREATE OR REPLACE PACKAGE Emp_data AS

TYPE Emp_val_cv_type IS REF CURSOR RETURN Emp_tab%ROWTYPE;

PROCEDURE Open_emp_cv (Emp_cv IN OUT Emp_val_cv_type,

Dept_number IN INTEGER);

PROCEDURE Fetch_emp_data (emp_cv IN Emp_val_cv_type,

emp_row OUT Emp_tab%ROWTYPE);

END Emp_data;

CREATE OR REPLACE PACKAGE BODY Emp_data AS

PROCEDURE Open_emp_cv (Emp_cv IN OUT Emp_val_cv_type,

Dept_number IN INTEGER) IS

BEGIN

OPEN emp_cv FOR SELECT * FROM Emp_tab WHERE deptno = dept_number;

END open_emp_cv;

PROCEDURE Fetch_emp_data (Emp_cv IN Emp_val_cv_type,

Emp_row OUT Emp_tab%ROWTYPE) IS

BEGIN

FETCH Emp_cv INTO Emp_row;

END Fetch_emp_data;

END Emp_data;

The following example shows how to call the Emp_data package procedures from a PL/SQL block:

DECLARE

-- declare a cursor variable

Emp_curs Emp_data.Emp_val_cv_type;

Dept_number Dept_tab.Deptno%TYPE;

Emp_row Emp_tab%ROWTYPE;

BEGIN

Dept_number := 20;

-- open the cursor using a variable

Emp_data.Open_emp_cv(Emp_curs, Dept_number);

-- fetch the data and display it

LOOP

Emp_data.Fetch_emp_data(Emp_curs, Emp_row);

EXIT WHEN Emp_curs%NOTFOUND;

DBMS_OUTPUT.PUT(Emp_row.Ename || ' ');

DBMS_OUTPUT.PUT_LINE(Emp_row.Sal);

END LOOP;

                                 END;
Implementing Variant Records
The power of cursor variables comes from their ability to point to different cursors. In
the following package example, a discriminant is used to open a cursor variable to
point to one of two different cursors:

CREATE OR REPLACE PACKAGE Emp_dept_data AS

TYPE Cv_type IS REF CURSOR;

PROCEDURE Open_cv (Cv IN OUT cv_type,

Discrim IN POSITIVE);

END Emp_dept_data;

CREATE OR REPLACE PACKAGE BODY Emp_dept_data AS

PROCEDURE Open_cv (Cv IN OUT cv_type,

Discrim IN POSITIVE) IS

BEGIN

IF Discrim = 1 THEN

OPEN Cv FOR SELECT * FROM Emp_tab WHERE Sal > 2000;

ELSIF Discrim = 2 THEN

OPEN Cv FOR SELECT * FROM Dept_tab;

END IF;

END Open_cv;

END Emp_dept_data;

You can call the Open_cv procedure to open the cursor variable and point it to either a
query on the Emp_tab table or the Dept_tab table. The following PL/SQL block
shows how to fetch using the cursor variable, and then use the ROWTYPE_MISMATCH
predefined exception to handle either fetch:

DECLARE

Emp_rec Emp_tab%ROWTYPE;

Dept_rec Dept_tab%ROWTYPE;

Cv Emp_dept_data.CV_TYPE;

BEGIN

Emp_dept_data.open_cv(Cv, 1); -- Open Cv For Emp_tab Fetch

Fetch cv INTO Dept_rec; -- but fetch into Dept_tab record

-- which raises ROWTYPE_MISMATCH

DBMS_OUTPUT.PUT(Dept_rec.Deptno);

DBMS_OUTPUT.PUT_LINE(' ' || Dept_rec.Loc);

EXCEPTION

WHEN ROWTYPE_MISMATCH THEN

BEGIN

DBMS_OUTPUT.PUT_LINE

('Row type mismatch, fetching Emp_tab data...');

FETCH Cv INTO Emp_rec;

DBMS_OUTPUT.PUT(Emp_rec.Deptno);

DBMS_OUTPUT.PUT_LINE(' ' || Emp_rec.Ename);

END;



时间: 2024-10-26 23:51:41

oracle中的游标 包 集合 的学习总结的相关文章

Oracle中的游标、硬解析、软解析、软软解析、解析失败

Oracle中的游标.硬解析.软解析.软软解析.解析失败 一. 游标的分类及共享游标 游标(Cursor)是Oracle数据库中SQL解析和执行的载体,它可以分为共享游标(Shared Cursor)和会话游标(Session Cursor).共享游标可以细分为父游标(Parent Cursor)和子游标(Child Cursor),可以通过视图V$SQLAREA和V$SQL来查看当前缓存在库缓存(Library Cache)中的父游标和子游标,其中V$SQLAREA用于查看父游标,V$SQL用

oracle中的程序包

一 程序包的基本概念 程序包可将若干函数或者存储过程组织起来,作为一个对象进行存储.程序包通常由两部分构成,规范(specification)和主体(body).程序报也可以包含常量和变量,包中的所有函数和存储过程都可以使用这些变量或者常量.   二 规范 1 创建规范(SQL窗口) create or replace package pkg_staff as        staffString varchar2(500);        stafftAge number:=18;      

如何在Oracle中使用游标来实现多重循环?[原创]

oracle|循环|游标|原创 这篇文章,是最近在写一个项目中所用的存储过程,由于是第一次接触oracle,其间花费了许多功夫,才把功能实现!特记录下来,以供参考!create or replace package PSH_GPRSSTREAMSTAT is   -- Author  : ADMINISTRATOR  -- Created : 2004-12-8 10:56:01  -- Purpose : GPRS流量统计状态  -- 统计GPRS流量   type    C_Cur is r

oracle中通过DBMS_CRYPTO包对表敏感字段进行加密

在安全越来越重视的近体,我们不少时候需要对数据库中的某个表的敏感列数据(银行卡,身份证号码,金额等)进行加密,方式数据泄密,在11.2.0.4中可以通过dbms_crypto包方式实现,增加oracle的加密效率,本文提供处理思路,其他可以根据需求尽情发挥 数据库版本 SQL> select * from v$version;   BANNER ----------------------------------------------------------------------------

Swift中内置的集合类型学习笔记_Swift

一.引言 Swift中提供了3种集合类型,Array数据类型,Set集合类型,Dictionary字典类型.Array用于存放一组有序的数据,数据角标从0开始一次递增:Set用于存放一组无序的数据,数据不可以重复:Dictionary也用于存放一组无序的数据,只是其是按照键值对的方式存储,键值必须唯一.这里借用官方文档中的一张图来表示3种集合类型的特点: 二.Array类型 Array通常也被称为数组,Swift是一种类型安全语言,其中的Array类型也必须确定其元素的类型,声明数组类型有两种方

oracle中游标(Cursor)的详解

概述 也许大家对数据库中游标都不陌生,但对于其概念可能有时又会有些模糊,游标到底是什么? 为了使大家对游标有个清晰的认识,本文将介绍Oracle中游标(curosr)相关的知识. 游标的概念 一般来讲,游标包含着两种不同的概念: 程序中的游标(Program Cursor)和Oracle中的游标(Oracle Curosr). 程序中的游标(Program Cursor): 在最终用户程序(Client Application)中,游标(curosr)通常指和SQL语句关联的一个数据结构,用于关

oracle中ora-0100错误打开游标过大的解决

最近做项目碰到ORA-01000错误,参考了一些解决办法,把自己解决问题的一些心得写下来.java访问oracle数据库,在for循环代码中,如果忽略关闭createstatment或preparedstatement建立的连接,将出现:ORA-01000错误.背景知识:oracle中每次使用用createstatment或preparedstatement语句,都将打开一个游标,所以单纯增 加oracle中打开游标数目不是解决问题的办法. 问题解决:1:首先定位是那些语句打开的游标过大.执行以

oracle中通过DBMS

 下面我们来看看oracle中通过DBMS_CRYPTO包对表敏感字段进行加密方法,有需要了解的朋友可一起来看看吧.   在安全越来越重视的近体,我们不少时候需要对数据库中的某个表的敏感列数据(银行卡,身份证号码,金额等)进行加密,方式数据泄密,在11.2.0.4中可以通过dbms_crypto包方式实现,增加oracle的加密效率,本文提供处理思路,其他可以根据需求尽情发挥 数据库版本 SQL> select * from v$version;   BANNER ---------------

oracle-求助诸君:EF调用Oracle包中带游标的存储过程

问题描述 求助诸君:EF调用Oracle包中带游标的存储过程 大家好,项目开发时遇到了瓶颈,是关于EF6调用Oracle包中带游标的存储过程,小弟尝试了N遍后,还是百试不得其解,望诸君助小弟一臂之力. Oracle packages如下:--------------分割线-----------------------------Oracle package bodies如下: ----------------------分割线----------------------------- 这是ADO