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等連接條件符合的某一個dept的emp表的數據作為一個集合存儲,而第二個沒有任何關聯條件,就是把所有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被用於EXP和IMP處理嵌套表。

  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);
  
--嵌套表的存儲:
--上例中,現實產生了兩張表:
/*
  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和嵌套表本身中索引的額外開銷。
               
                以上參考oracle高級專家編程。
*/

 

來自:http://www.itpub.net/thread-640129-1-1.html 謝謝作者!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM