oracle集合&对象

一,集合

集合,遵循面向对象风格的现代编程,包含三种类型:

  1. 变长数组(varry),类似于java,c++中的数组,可以用于存储有序的元素集合,每个元素 一个索引,记录元素在数组的位置;需要注意的是,变长数组修改只能整体修改,有最大大小,初始化设置,但是可以修改
  2. 嵌套表 嵌套在另外一个表中的表,可以插入,更新,删除桥套标中的单个元素,比变长数组灵活,并且没有最大大小
  3. 关联数组 类似于java的哈西表,是一个键值对集合。不过只能用在PLSQL中,不能存储在数据库

1, 变长数组

SQL> set serveroutput on
SQL> edit
已写入 file afiedt.buf

  1  DECLARE
  2    -- 定义varray 定义size ,of varchar2(10) 定义类型
  3    TYPE arry_var IS VARRAY(3) OF VARCHAR2(10);
  4    arry_name arry_var;
  5  BEGIN
  6    -- init array
  7    arry_name := arry_var('china', 'japan','usa');
  8    dbms_output.put_line(arry_name(1));
  9* END;
 10
 11  /
china

PL/SQL 过程已成功完成。

修改长度

SQL> create  TYPE arry_var IS VARRAY(3) OF VARCHAR2(10);
  2  /

类型已创建。

SQL> alter type arry_var modify limit 10 cascade;

类型已变更。

SQL> create table table_array1(id int,name arry_var);

表已创建。
最后使用变长数组类型定义表列

2, 嵌套表

SQL> edit
已写入 file afiedt.buf

  1  create type t_obj1 as object(
  2* id int,name varchar2(10));
SQL> l
  1  create type t_obj1 as object(
  2* id int,name varchar2(10));
SQL> /

类型已创建。

SQL> create type t_nested_table1 as table of t_obj1;
  2  /

类型已创建。

SQL> edit
已写入 file afiedt.buf

  1  create table t_nested_table (id int,desc1 t_nested_table1)
  2  nested table
  3  desc1
  4* store as desc2
SQL> /

表已创建。

这里创建了嵌套表类型t_nested_table1,他使用了 t_obj1的对象类型,

最后使用嵌套表类型定义表列,表后面用nested table字句标识了嵌套表列名称,store as指定实际嵌套表的名称

其他例子跟record区别的:

--例子1:
drop table emp;
create table emp(empno int,ename varchar2(20),hiredate date,deptno int);

DECLARE  
   TYPE emp_rec_type IS RECORD  
   (  
      empno      emp.empno%TYPE  
     ,ename      emp.ename%TYPE  
     ,hiredate   emp.hiredate%TYPE  
   );  
   TYPE nested_emp_type IS TABLE OF emp_rec_type;  
   emp_tab   nested_emp_type;  
BEGIN  
   DELETE FROM emp  
   WHERE  deptno = 20  
   RETURNING empno, ename, hiredate     -->使用returning 返回这几个列   
   BULK   COLLECT INTO emp_tab;         -->将前面返回的列的数据批量插入到集合变量     
end;


--对比1:
create or replace type emp_rec_type IS object
   (
      empno      NUMBER(4)
     ,ename      VARCHAR2(10)
     ,hiredate   DATE
   );

DECLARE  
   TYPE nested_emp_type IS TABLE OF emp_rec_type;  
   emp_tab   nested_emp_type;  
BEGIN  
   DELETE FROM emp  
   WHERE  deptno = 20  
   RETURNING emp_rec_type(empno, ename, hiredate)     -->使用returning 返回这几个列   
   BULK   COLLECT INTO emp_tab;         -->将前面返回的列的数据批量插入到集合变量     
end;

-- 例子2
create table t1 (id int,name varchar2(100));
insert into t1 values(1,'1234');
insert into t1 values(2,'1234');

declare
cnt int;
type type1 is record(id int,name varchar2(10)); -- 改为object错误
type v_loop_tab1 is table of type1;
v1_lt v_loop_tab1;
begin
cnt :=1000;
while(cnt>0) loop
select * bulk collect into v1_lt from t1;
cnt:=cnt-1;
end loop;
end;

3,关联数组

关联数组其实是在oracle10g中加入的,是一个键值对集合,可以使用一个键值或者整数访问数组中的值

使用1

set serveroutput on
declare
  type nest_table1  is table of varchar2(15) index by binary_integer;
  -- 指定是一个集合的表的数组类型, 简单的来说就是一个可以存储一列多行的数据类型
  -- INDEX BY BINARY_INTEGER  指索引组织类型
  v_arr_table nest_table1;
  cnt int;
begin
  v_arr_table(1) := 'china';
  v_arr_table(2) := 'USA';
  
  cnt := v_arr_table.count;
  for i in 1 .. cnt loop
    dbms_output.put_line(v_arr_table(i));
    end loop;
end;
使用2

reate table country
(
  id int,
  name varchar2(15)
);
insert into country values(1,'china');
insert into country values(2,'USA');
commit;

set serveroutput on
declare
type t_r_country is record(
  id country.id%type,
  name country.name%type
  );
  type t_array_country is table of t_r_country index by binary_integer;
  --或者这里使用
  type t_array_country1 is table of country%rowtype index by binary_integer;
  v_array_country t_array_country;
  v_array_country1 t_array_country1;
begin
  select id,name bulk collect into v_array_country from country;
  for i in 1 .. v_array_country.count loop
    dbms_output.put_line(v_array_country(i).name);
    end loop;
    
  for i in 1 .. v_array_country.count loop
    dbms_output.put_line(v_array_country(i).name);
    end loop;
end;
使用3

declare
	type emp_table_type is table of emp%rowtype index by binary_integer;--这是类型声明
	type ename_table_type is table of emp.ename%type;--这是类型声明
	emp_table emp_table_type;--这里是定义变量
	ename_table ename_table_type;--这里是定义变量
begin
	--没有index by需要初始化才能使用,否则会报错:变量未初始化
	ename_table:= ename_table_type();
	for v_ind in 1..20 loop
	ename_table.extend;--每次添加元素都要extend
	ename_table.(v_ind):='Ename' || v_ind;

	--index by只要定义就可以直接用,无需初始化
	emp_table(v_ind).ename:='Ename' || v_ind;
	emp_table(v_ind).sal:=1000* v_ind;
	end loop;
end;

使用4

SQL> edit
已写入 file afiedt.buf

  1  declare
  2  v_table_name varchar2(100);
  3  TYPE type_array_str IS TABLE OF VARCHAR2(32) INDEX BY VARCHAR(32);
  4  v_array_table type_array_str;
  5  begin
  6    v_array_table('china') := 'good';
  7    v_array_table('usa') := 'bad';
  8    v_table_name := v_array_table.FIRST;
  9  loop
 10       exit when v_table_name is null;
 11       dbms_output.put_line(v_array_table(v_table_name));
 12       dbms_output.put_line(v_table_name);
 13       v_table_name := v_array_table.next(v_table_name);
 14  end loop;
 15* end;
SQL> /
good
china
bad
usa

PL/SQL 过程已成功完成。

二,对象

面向对象编程语言,java,c++都允许定义类,当然oracle也支持对象操作

对象示例1

SQL> edit
已写入 file afiedt.buf

  1  create or replace type obj_country is object(
  2   id int,
  3   name varchar2(15),
  4   member function get_sysdate return date
  5* );
  6  /

类型已创建。

SQL> edit
已写入 file afiedt.buf

  1  create or replace type body obj_country as
  2   member function get_sysdate return date is
  3     v_sysdate date;
  4   begin
  5     select sysdate into v_sysdate
  6     from dual;
  7     return v_sysdate;
  8   end;
  9* end;
SQL> /

类型主体已创建。

SQL> create table obj_t1 ( id int,desc1 obj_country);

表已创建。

SQL> insert into obj_t1(id,desc1)
  2  values(1,obj_country(1,'china'));

已创建 1 行。

SQL> commit;

提交完成。

SQL> select * from obj_t1;

        ID
----------
DESC1(ID, NAME)
---------------------------------------------------------------------

         1
OBJ_COUNTRY(1, 'china')


SQL> select t.desc1.get_sysdate() from obj_t1 t;

T.DESC1.GET_SY
--------------
06-1月 -18
对象示例2

create or replace type obj_country is object(id int,name varchar2(15));

create or replace type tab_country is  table of obj_country ;
set serveroutput on
declare
  v_array_country tab_country := tab_country();
begin
for cur in (select id,name from country) loop
    v_array_country.extend;
    v_array_country(v_array_country.count) :=obj_country(cur.id,cur.name);
    end loop;
end;

三,集合应用与批量提交的一些场景

使用bulk collect+forall 加速批量提交

批量提交占用较少的undo,资源快速释放,并且他适合批量操作

不管是显示游标还是隐式游标,都可以通过BULK COLLECT在数据库的单次交互中获取多行数据。BULKCOLLECT相对Cursor Loop方式减少了PL/SQL引擎和SQL引擎之间切换次数,因此也减少了提取数据时的额外开销;通过limit rows限制提取记录数,减少对PGA的消耗,避免换页产生;FORALL告诉PL/SQL引擎要先把一个或多个集合的所有成员都绑定到SQL语句中,然后再把语句发送给SQL引擎,如果for ..loop 循环,那么会发送n次,而用Forall,一次行全部发送过去

-- 环境准备
create table big_ta (id int,name varchar2(20),datavalue number);
insert into big_ta values(1,'china',1.90);
insert into big_ta values(1,'china',1.90);
insert into big_ta values(2,'usa',1.00);
insert into big_ta values(2,'usa',2.00);
insert into big_ta select rownum,object_name,1.0 from dba_objects;
insert into big_ta select * from big_ta;
commit;

create table big_tb (id int,name varchar2(20),datavalue number);

以下是批量插入,删除,更新操作

-- 插入
declare
  TYPE ARRAY1 IS TABLE OF big_tb%ROWTYPE;
  l_data ARRAY1;
  CURSOR c IS
    SELECT * FROM big_ta;
    
BEGIN
  OPEN c;
  LOOP
    FETCH c BULK COLLECT
      INTO l_data LIMIT 5000;
    FORALL i IN 1 .. l_data.COUNT 
      INSERT /*+append*/
      INTO big_tb
      VALUES l_data
        (i);
    commit;
    EXIT WHEN c%NOTFOUND;
  END LOOP;
  CLOSE c;
  end;


--delete

DECLARE
  CURSOR mycursor IS
    SELECT rowid FROM big_ta WHERE id = 1;
  TYPE rowid_table_type IS TABLE OF rowid index by pls_integer;
  v_rowid rowid_table_type;
BEGIN
  OPEN mycursor;
  LOOP
    FETCH mycursor BULK COLLECT
      INTO v_rowid LIMIT 5000;
    EXIT WHEN v_rowid.count = 0;
    FORALL i IN v_rowid.FIRST .. v_rowid.LAST
      DELETE big_ta WHERE rowid = v_rowid(i);
    COMMIT;
  END LOOP;
  CLOSE mycursor;
END;
/


-- update

DECLARE
  CURSOR mycursor IS
    SELECT id FROM big_ta WHERE name = 'usa';
  TYPE num_tab_t IS TABLE OF NUMBER;
  v_pk_tab NUM_TAB_T;
BEGIN
  OPEN mycursor;
  LOOP
    FETCH mycursor BULK COLLECT
      INTO v_pk_tab LIMIT 5000;
    EXIT WHEN v_pk_tab.count = 0;
    FORALL i IN v_pk_tab.FIRST .. v_pk_tab.LAST
      UPDATE big_ta SET datavalue = datavalue+1  WHERE id = v_pk_tab(i);
    COMMIT;
  END LOOP;
  CLOSE mycursor;
END;
/



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

朝闻道-夕死可矣

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值