一、介绍 

1、定义

嵌套表是表中之表。一个嵌套表是某些行的集合,它在主表中表示为其中的一列。对主表中的每一条记录,嵌套表可以包含多个行。在某种意义上,它是在一个表中存储一对多关系的一种方法。
    简单的说:就是把一个表中的字段定义为一个表,这个字段表的数据存储在外部的一个表中。嵌套表可以有效地代替多个表之间的连接。

补充:

当需要存储与表有关的数据时,可选的方案包括:可变数组、嵌套表、独立表。三种方案有什么区别,或者说什么情况下适用呢?

(1)可变数组:可变数组是不能被索引的,当记录量很大时,可变数组就会遇到性能问题,此外,从可变数组中查询数据比较困难,因此,当行数有限时,使用可变数组比较合适。

(2)嵌套表:嵌套表可以被索引,它是对象类型,故有与之关联的方法。所以,当需要将数据与方法联系在一起时,需要考虑使用嵌套表。

(3)关系表:关系表最大的好处是可以灵活地与多表关联,当数据需要与多表关联时,推荐使用标准关系表。

参考:《Oracle Database 12C完全参考手册》

2、Oracle提供两种使用嵌套表的方法

(1).PL/SQL代码中作为扩展PL/SQL语言;(这部分内容就是上边所说Oracle内存表是oracle嵌套表的部分功能)
  (2).作为物理存储机制,以持久地存储集合(比较少)。

3、嵌套表的特点

1、对象复用:如果编写面向对象的代码,就提高了重用以前编写的代码模块的机会。同样,如果创建面向对象的数据库对象,也就提高了数据库对象能够被重用的机会。
    2、标准支持:如果创建标准的对象,那么它们被重用的机会就会提高。如果有多个应用或多个表使用同一数据库对象集合,那么它就是既成事实的数据库对象标准。
    3、定义访问路径:对于每一个对象,用户可定义在其上运行的过程和函数,从而可以使数据和访问此数据的方法联合起来。有了用这种方式定义的访问路径,就可以标准化数据访问的方法并提高对象的可复用性。

二、测试

1、创建测试表emp、dept

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) ,
 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;

2、创建类型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)
);

3、创建嵌套表emp_tab_type

  该表可以被嵌套在其他表中,它的字段就是emp_type中的字段

CREATE OR REPLACE TYPE emp_tab_type AS TABLE OF emp_type;

4、对自定义类型初始化

如果嵌套表是直接参照一个物理表的结构创建的,则可以直接使用,如果嵌套表是自己定义的一个record,并根据record创建的嵌套表,则在使用时需要为record初始化,否则会报错

create or replace procedure mytest2 is
CURSOR all_emps IS
SELECT * FROM emp;
TYPE emp_table IS TABLE OF emp_tab_type;
emps emp_table;
I PLS_INTEGER;
l_count PLS_INTEGER;
BEGIN
l_count := 0;
emps := emp_table(); -- 初始化嵌套表并产生一条空记录
FOR c1 IN all_emps LOOP
l_count := l_count + 1;
emps.EXTEND;
emps(l_count) := emp_tab_type(null,null,null,null,null,null,null);
emps(l_count).empno := c1.empno;
emps(l_count).ename := c1.ename;
emps(l_count).job := c1.job;
emps(l_count).mgr := c1.mgr;
emps(l_count).hiredate := c1.hiredate;
emps(l_count).sal := c1.sal;
emps(l_count).comm := c1.comm;
END LOOP; -- clone the first entry five times
emps.EXTEND(5, 1); FOR i IN 1 .. l_count + 5 LOOP
DBMS_OUTPUT.PUT_LINE(TO_CHAR(emps(i).empno) || ' ');
END LOOP;
END;

5、使用嵌套表

CREATE TABLE dept_and_emp(
 deptno NUMBER(2) PRIMARY KEY,
 dname VARCHAR2(14),
 loc VARCHAR2(13),
 emps emp_tab_type --在表中再定义一个表,即emp_tab_type表,它就是嵌套在dept_and_emp中的表,也就是嵌套表。
--它和主表dept_and_emp之间是主从关系,即一条主表记录对应一个嵌套表中的多条记录。
)
NESTED TABLE emps STORE AS emps_nest; --emps_nest是嵌套表列的存储表

6、插入数据

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;

注意:只有“4”行被创建。实际上在DEPT_AND_EMP表中只有4行。14个EMP行实际上不能独立存在。

注意提交commit;

7、查询插入结果

Oracle同样提供方法table()去掉集合的嵌套,像关系型表一样处理(能够将EMPS列当作一个表,并自然连接且不需要连接条件):

SELECT d.deptno, d.dname, emp.* FROM dept_and_emp D, TABLE(d.emps) emp;

8、更新记录

按照“每行实际是一张表”的思想来更新:

UPDATE TABLE( SELECT emps FROM dept_and_emp WHERE deptno = 10) SET comm = 100;

9、插入

INSERT INTO TABLE
(SELECT emps FROM dept_and_emp WHERE deptno = 10)
VALUES
(1234, 'NewEmp', 'Clerk', 7782, SYSDATE, 1200, NULL); SELECT a.deptno, a.dname, EMP.* FROM dept_and_emp A, TABLE(A.EMPS) EMP; --查看结果,已经添加记录

10、删除  

DELETE FROM TABLE (SELECT emps FROM dept_and_emp WHERE deptno = 10)
WHERE ename = 'NewEmp'; SELECT a.deptno, a.dname, EMP.* FROM dept_and_emp A, TABLE(A.EMPS) EMP;; --查看结果已经删除记录

补充:

一般而言,必须总是连接,而不能单独查询嵌套表(如emp_nest)中的数据,但是如果确实需要,是可以的:

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

而察看EMPS_NEST的结构看不到NESTED_TABLE_ID,SYS_NC_ROWINFO$两列。对父表DEPT_AND_EMP来说NESTED_TABLE_ID是一个外键。
使用这个hint就可以直接操作嵌套表了:

UPDATE /*+NESTED_TABLE_GET_REFS+*/ emps_nest SET ename=INITCAP(ename);

参考材料:

《Oracle专家高级编程》
plsql使用自定义的嵌套表-http://blog.csdn.net/majian_1987/article/details/8557082?locationNum=14
oracle自定义类型-http://www.cnblogs.com/advocate/p/3729998.html
Oracle提供两种使用嵌套表 - http://blog.csdn.net/rudygao/article/details/25240427
oracle 嵌套表- http://www.cnblogs.com/oldcat/archive/2011/09/17/2179928.html
oracle 嵌套表- http://www.cnblogs.com/starzhao/archive/2010/05/19/1739234.html

Oracle嵌套表的更多相关文章

  1. oracle 嵌套表

    --自定义对象 CREATE OR REPLACE TYPE Fas_checksheetinfo_line_obj AS OBJECT(  CSID_ID           VARCHAR2(32 ...

  2. (转)oracle嵌套表示例

    本文转载自:http://www.cnblogs.com/gisdream/archive/2012/04/13/2445291.html ----嵌套表:就是把一个表中的字段定义为一个表,这个字段表 ...

  3. oracle ibatis 存储过程 返回游标 嵌套表

    自己解决问题了 问题总结: 1.index by表不能存储在数据库中的type中,故选择嵌套表. 2.ibatis不支持oracle的复合数据类型的返回.(个人理解) 3.替代方案:用返回oracle ...

  4. oracle:变长数组varray,嵌套表,集合

    创建变长数组类型 ) );  这个变长数组最多可以容纳两个数据,数据的类型为 varchar2(50) 更改元素类型的大小或精度 可以更改变长数组类型和嵌套表类型 元素的大小. ALTER TYPE ...

  5. oracle 之 数组、嵌套表、SQL查询式 实现多表数据for循环插入指定表

    1.基础环境 创建基础表: CREATE TABLE TEST_TAB1( ID INT, NAME VARCHAR2(20) ); CREATE TABLE TEST_TAB2( ID INT, N ...

  6. PL/SQL 嵌套表变长数组和索引表[转]

    关于PL/SQL中这三种数组的介绍,不想写了.转一篇日志吧…… 链接:http://www.blogjava.net/decode360/archive/2008/08/08/280825.html ...

  7. Oracle的表连接方式

    Oracle的表连接方式: 1.Nl Join连接(嵌套连接) 2.Hash Join(哈希连接) 3.Merge Sort Join(排序合并连接) 各种连接的使用场景: 1. 排序合并连接是偏向于 ...

  8. Oracle多表的简单查询

    Oracle多表的简单查询 .多表查询 多表查询是指基于两个和两个以上的表或是视图的查询. 问题:显示雇员名,雇员工资及所在部门的名字[笛卡尔集]? select t.ename,t.sal,t1.d ...

  9. 嵌套表用法详解(PLSQL)

    嵌套表 嵌套表是一种类似于索引表的结构,也可以用于保存多个数据,而且也可以保存复合类型的数据 嵌套表指的是一个数据表定义事同时加入了其他内部表的定义,这一概念是在oracle 8中引入的,它们可以使用 ...

随机推荐

  1. autoboxing and unboxing

    Why does 128==128 return false but 127==127 return true public static void autoboxingUnboxing(){ Int ...

  2. UVAlive5135_Mining Your Own Business

    好题.给一个无向图,求最少染黑多少个点后,使得任意删除一个点,每一个点都有与至少一个黑点联通. 一开始的确不知道做.看白书,对于一个联通分量,如果它有两个或以上的割点,那么这个分量中间的任何一个点都是 ...

  3. zabbix自定义web检测

    zabbix自定义web检测 本博客使用zabbix 版本 4.0.3 Web监控的原理 Web监控即对HTTP服务的监控,模拟用户去访问网站,对特定的结果进行比较,如状态码.返回字符串等特定的数据进 ...

  4. #46 delete(动态规划+树状数组)

    二维的dp非常显然,但这也没有什么优化的余地了. 注意到最后的方案中只有产生贡献的位置是有用的,剩下的部分可以在该范围内任意选取. 所以我们考虑设f[i]为i号位最后产生贡献的答案,则f[i]=max ...

  5. 【刷题】BZOJ 2049 [Sdoi2008]Cave 洞穴勘测

    Description 辉辉热衷于洞穴勘测.某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道连接了恰好 ...

  6. 【刷题】BZOJ 2002 [Hnoi2010]Bounce 弹飞绵羊

    Description 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置 ...

  7. Swift使用SDWebImage处理远程图片资源

    第一步:配置SDWebImage 打开github,https://github.com/rs/SDWebImage,将SDWebImage下载到本地 用Xcode创建一个swift的singleVi ...

  8. 【BZOJ1922】大陆争霸(最短路)

    [BZOJ1922]大陆争霸(最短路) 题面 BZOJ 洛谷 题解 最短路变形题. 定义\(dis\)表示最短路,\(d\)表示最早可以进入当前点的时间.显然\(d=max(max(dis_v,d_v ...

  9. 解题:POI 2008 Subdivision of Kingdom

    题面 还可以这么搜......学到了(PoPoQQQ orz) 我们最朴素的做法是枚举所有状态(当然可以剪,剪完最终实际状态量也是$C_{26}^{13}$的),然后每次$O(n)$扫一遍判断,大概会 ...

  10. django中模板变量与内置标签以及过滤器

    本文参考 官方文档 . 一  模板变量 格式: {{ variable_name }} variable_name   命名规则与变量命名规则类似,允许字符数字下划线,不允许标点. variable_ ...