嵌套表

一、嵌套表的定义:

   
嵌套表是表中之表。一个嵌套表是某些行的集合,它在主表中表示其中的一列。主表中的一条记录,嵌套表可以包含多个行。在某上,它是在一个表中存系的一方法。考一个包含部信息的表,在任何时间个部会有很多目正在施。在一个格的系模型中,将需要建立两个独立的表departmentproject.

   
嵌套表允department表中存放目的信息。勿需合操作,就可以通department表直接访问项目表中的记录这种经联合而直接选择数据的能力使得用户对访问更加容易。甚至在并没有定方法来访问嵌套表的情况下,也能很清楚地把部目中的数据系在一起。在格的系模型中,departmentproject两个表的系需要通外部关键字(外系才能实现


二、浅析oracle嵌套表
以前在做表的候会常用到oracle的内存表(oracle嵌套表的部分功能,里在下)来提高性能。
利用oracle内存表临时运算通ref cursor来返回我想要的果集。
open cur for select * from table(fun_to_table_rb1_1(cur_qc,cur_qm));
部分的一些测试可以参看:http://www.itpub.net/showthread.php?threadid=617298

最近把oracle嵌套表的其他功能仔看了看并做了个简单整理。

oracle提供两使用嵌套表的方法:
1. PL/SQL中作为扩PL/SQL言;(部分内容就是上oracle内存表是oracle嵌套表的部分功能)
2 物理存机制,以持久地存集合。

*/

--测试表:

CREATE TABLE dept
  (deptno NUMBER(2) PRIMARY KEY,
   dname VARCHAR2(14),
   loc VARCHAR2(13)
  );
  
CREATE TABLE emp
  (empno NUMBER(4) PRIMARY KEY,
   ename VARCHAR2(10),
   job VARCHAR2(9),
   mgr NUMBER(4) REFERENCES emp,
   hiredate DATE,
   sal NUMBER(7,2),
   comm NUMBER(7,2),
   deptno NUMBER(2) REFERENCES dept
  );
  
INSERT INTO dept SELECT * FROM scott.dept;
INSERT INTO emp SELECT * FROM scott.emp;

--建type

CREATE OR REPLACE TYPE emp_type AS OBJECT
  (empno NUMBER(4),
   ename VARCHAR2(10),
   job VARCHAR2(9),
   mgr NUMBER(4),
   hiredate DATE,
   sal NUMBER(7,2),
   comm NUMBER(7,2)
  );
  
CREATE OR REPLACE TYPE emp_tab_type AS TABLE OF emp_type;

--使用嵌套表

CREATE TABLE dept_and_emp
  (deptno NUMBER(2) PRIMARY KEY,
   dname VARCHAR2(14),
   loc VARCHAR2(13),
   emps emp_tab_type
  )
  NESTED TABLE emps STORE AS emps_nest;

--可以在嵌套表上增加(里我先不行此步骤,等做完下一步测试束)
--ALTER TABLE emps_nt ADD CONSTRAINT emps_empno_unique
--嵌套表不支持参照完整性束,不能参考任何其他表甚至自己
--给嵌套表增加数据,我看看方式的果有何不同
方式1:INSERT INTO
  dept_and_emp
  SELECT dept.*,
   CAST(
  MULTISET( SELECT empno, ename, job, mgr, hiredate, sal,
  comm
   FROM
  emp
   WHERE emp.deptno
  = dept.deptno ) AS emp_tab_type )
   FROM
  dept;
--Oracle提供方法去掉集合的嵌套,像系型表一样处理(能EMPS列当作一个表,并自然接且不需要接条件):
SELECT d.deptno, d.dname, emp.* FROM dept_and_emp D, TABLE(d.emps) emp;
--这行看到果是14条数据

delete from dept_and_emp;

方式2:INSERT INTO dept_and_emp
SELECT dept.*, CAST(MULTISET( SELECT empno, ename, job, mgr, hiredate, sal, comm
  FROM
  emp,dept
   WHERE emp.deptno
  = dept.deptno ) AS emp_tab_type ) from dept;

SELECT d.deptno, d.dname, emp.* FROM dept_and_emp D, TABLE(d.emps) emp;
--行看到果是56条数据,然是错误

--第一个是按照where接条件符合的某一个deptemp表的数据作一个集合存,而第二个没有任何关联条件,就是把所有emp的数据
--全部作一个dept的数据存个写法然是错误的,如果我嵌套表加上,就可以起到防止这种错误的功效了。

--增加束再行我的第二个insert句将会报错
--我按照上第一个insert句插入数据,继续测试

--按照实际是一的思想来更新:
UPDATE TABLE( SELECT emps FROM dept_and_emp WHERE deptno = 10) SET comm = 100;

--插入与除的法:
  INSERT INTO TABLE(SELECT emps FROM dept_and_emp WHERE deptno=10)
  VALUES (1234,'NewEmp','Clerk',7782,SYSDATE,1200,NULL);
  
  DELETE FROM TABLE(SELECT emps FROM dept_and_emp WHERE deptno=20)
  WHERE ename='SCOTT';

--一般而言,必须总接,而不能查询嵌套表(如emp_nest)中的数据,但是如果确需要,是可以的。
--hint NESTED_TABLE_GET_REFS被用于EXPIMP理嵌套表。

  SELECT /*+NESTED_TABLE_GET_REFS+*/ NESTED_TABLE_ID, SYS_NC_ROWINFO$ FROM emps_nest;

--而察看EMPS_NEST构看不到NESTED_TABLE_ID,SYS_NC_ROWINFO$两列。父表DEPT_AND_EMPNESTED_TABLE_ID是一个外
--使用hint就可以直接操作嵌套表了:
  UPDATE /*+NESTED_TABLE_GET_REFS+*/ emps_nest SET ename=INITCAP(ename);
  
--嵌套表的存储:
--上例中,现实产生了两表:
/*
  DEPT_AND_EMP
  (deptnob NUMBER(2),
  dname VARCHAR2(14),
  loc VARCHAR2(13),
  SYS_NC0000400005$,
RAW(16))
  
  EMPS_NEST
  (SYS_NC_ROWINFO$,
  NESTED_TABLE_ID,
RAW(16),
  empno NUMBER(4),
  ename VARCHAR2(10),
  job VARCHAR2(9),
  mgr NUMBER(4),
  hiredate DATE,
  sal NUMBER(7,2),
  comm NUMBER(7,2)) 
*/ 
--况下,个嵌套表列都生一个外的RAW(16)藏列,并在其上建了唯一束,用以指向嵌套表。而嵌套表中有两个
--隐藏列:SYS_NC_ROWINFO$是作一个象返回所有量元素的一个列;另一个NESTED_TABLE_ID的外回指向父表。
--可以看到真
/*
  CREATE TABLE DEPT_AND_EMP
  (DEPTNO NUMBER(2,0),
   DNAME VARCHAR2(14),
   LOC VARCHAR2(13),
   EMPS EMP_TAB_TYPE)
  PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
  LOGGING STORAGE(INITIAL 131072 NEXT 131072
  MINEXTENTS 1 MAXEXTENTS 4096
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUP 1
  BUFFER_POOL DEFAULT)
  TABLESPACE USER
  NESTED TABLE EMPS
  STORE AS EMPS_NEST
  RETURN BY VALUE;
  
  RETURN BY VALUE用来描述嵌套表如何返回到客户应用程序中。
  NESTED_TABLE_ID列必是索引的,那么较好的解决法就是使用IOT嵌套表。
  CREATE TABLE DEPT_AND_EMP
  (DEPTNO NUMBER(2,0),
   DNAME VARCHAR2(14),
   LOC VARCHAR2(13),
   EMPS EMP_TAB_TYPE)
  PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
  LOGGING STORAGE(INITIAL 131072 NEXT 131072
  MINEXTENTS 1 MAXEXTENTS 4096
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUP 1
  BUFFER_POOL DEFAULT) TABLESPACE USER
  NESTED TABLE EMPS
  STORE AS EMPS_NEST
  ((empno NOT NULL,
UNIQUE(empno),
PRIMARY KEY(nested_table_id,empno))
  ORGANIZATION
  INDEX COMPRESS 1)
  RETURN BY VALUE;
  
  这样与最初默的嵌套表相比,使用了少的存并有最需要的索引。
  不使用嵌套表作永久存机制的原因
  1.增加了RAW(16)列的开销,父表和子表都将增加外的列;
  2.当通常已有唯一,父表上的唯一束是开销
  3.没有使用不支持的构(NESTED_TABLE_GET_REFS),嵌套表不容易使用。
  一般推荐在构和视图中使用嵌套表。如果要使用嵌套表作机制,
确保嵌套表是IOT,以避免NESTED_TABLE_ID和嵌套表本身中索引的开销

三、补充

1cast:转换成指定的数据型。

2multiset:转换成定好的型。

3、 table()函数

参考http://www.itpub.net/showthread.php?threadid=617298

PL/SQL表---table()函数用法


/*

PL/SQL表---table()函数用法:
利用table()函数,我可以将PL/SQL返回的果集代替table

simple example

1、table()合数

*/

create or replace type t_test as object(
id integer,
rq date,
mc varchar2(60)
);

create or replace type t_test_table as table of t_test;

create or replace function f_test_array(n in number default null) return t_test_table
as
v_test t_test_table := t_test_table();
begin
        for i in 1 .. nvl(n,100) loop
                v_test.extend();        --   append   one   null   element
                                                  --   为增加的元素赋值,如果没用EXTEND里会出
                v_test(v_test.count) := t_test(i,sysdate,'mc'||i);
        end loop;
        return v_test;
end f_test_array;
/

select * from table(f_test_array(10));

/*

2table()PIPELINED函数:

*/

create or replace function f_test_pipe(n in number default null) return t_test_table PIPELINED
as
v_test t_test_table := t_test_table();
begin
        for i in 1 .. nvl(n,100) loop
                pipe row(t_test(i,sysdate,'mc'||i));
        end loop;
return;
end f_test_pipe;
/

select * from table(f_test_pipe(20));

/*

3、table()合系包:

*/

create table test (id varchar2(20));
insert into test values('1');
commit;
explain plan for select * from test;
select * from table(dbms_xplan.display);

4、上述所用函数解释
extend():        Oracle   逻辑上是由各个表空(tablespace)构成的,
                            tablespacesegments()构成
                            段是由extends构成   中文叫作区   或者数据区
                           区是由一个一个的数据构成   数据的大小由操作系决定。
PIPELINED  pipe row
                  
参考  http://edu.cnzz.cn/NewsInfo/15746.aspx
                     Pipelined Table实现split函数的示例
   split作用: 比如把一个字符串A,B,C,D,E   根据逗号分隔,转换成一个数,数中的个元素是
                  A
                  B
                  C
                  D
                  E

               
实际用中,PL/SQL 函数返回数据的多个行,必返回一个 REF CURSOR 或一个数据集合来完成。REF CURSOR 这种情况局限于可以从查询选择的数据,而整个集合在可以返回前,必须进行具体化。

Oracle 9i 通引入的管道化表函数正了后一情况。表函数是返回整个行的集(通常作一个集合)的函数,可以直接从 SQL 句中查询,就好像它是一个真正的数据表一。管道化表函数与之相似,但是它像在构建返回数据,而不是一次全部返回。管道化表函数更加有效,因数据可以尽可能快地返回。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值