- Nested tables may be modified (inserted/updated/deleted) from, using SQL.
rajesh@10GR2> create type person_add as object(
2 street_address1 varchar2(40),
3 street_address2 varchar2(40),
4 city varchar2(40),
5 state varchar2(40),
6 zip number
7 );
8 /
Type created.
Elapsed: 00:00:00.09
rajesh@10GR2>
rajesh@10GR2> create type person_typ is table of person_add;
2 /
Type created.
Elapsed: 00:00:00.12
rajesh@10GR2>
rajesh@10GR2> create table person(
2 person_id number,
3 first_name varchar2(30),
4 last_name varchar2(30),
5 address person_typ
6 ) nested table address store as address_ntt;
Table created.
Elapsed: 00:00:00.17
rajesh@10GR2>
rajesh@10GR2> insert into person values (1,'Test1','Test1',person_typ(
2 person_add('123 main1',null,'CA','MN',123),
3 person_add('245 main1',null,'NJ','MN',245))
4 );
1 row created.
Elapsed: 00:00:00.01
rajesh@10GR2> commit;
Commit complete.
Elapsed: 00:00:00.01
rajesh@10GR2> select p_add.street_address1,p_add.street_address2
2 from person p,table(p.address) p_add;
STREET_ADDRESS1 STREET_ADDRESS2
---------------------------------------- ----------------------------------------
123 main1
245 main1
Elapsed: 00:00:00.04
rajesh@10GR2>
rajesh@10GR2> update table (select address from person)
2 set street_address2 = street_address1;
2 rows updated.
Elapsed: 00:00:00.01
rajesh@10GR2>
rajesh@10GR2> select p_add.street_address1,p_add.street_address2
2 from person p,table(p.address) p_add;
STREET_ADDRESS1 STREET_ADDRESS2
---------------------------------------- ----------------------------------------
123 main1 123 main1
245 main1 245 main1
Elapsed: 00:00:00.03
rajesh@10GR2>
rajesh@10GR2> delete from table (select address from person);
2 rows deleted.
Elapsed: 00:00:00.01
rajesh@10GR2>
rajesh@10GR2> select p_add.street_address1,p_add.street_address2
2 from person p,table(p.address) p_add;
no rows selected
Elapsed: 00:00:00.00
rajesh@10GR2>
rajesh@10GR2>
- VARRAYs must be procedurally modified. You cannot: UPDATE , DELETE as you could with a nested table
rajesh@10GR2> create type person_add as object(
2 street_address1 varchar2(40),
3 street_address2 varchar2(40),
4 city varchar2(40),
5 state varchar2(40),
6 zip number
7 );
8 /
Type created.
Elapsed: 00:00:00.09
rajesh@10GR2>
rajesh@10GR2> create type person_typ is Varray(3) of person_add;
2 /
Type created.
Elapsed: 00:00:00.04
rajesh@10GR2> create table person(
2 person_id number,
3 first_name varchar2(30),
4 last_name varchar2(30),
5 address person_typ
6 );
Table created.
Elapsed: 00:00:00.04
rajesh@10GR2>
rajesh@10GR2> insert into person values (1,'Test1','Test1',person_typ(
2 person_add('123 main1',null,'CA','MN',123),
3 person_add('245 main1',null,'NJ','MN',245))
4 );
1 row created.
Elapsed: 00:00:00.01
rajesh@10GR2> commit;
Commit complete.
Elapsed: 00:00:00.03
rajesh@10GR2> select p_add.street_address1,p_add.street_address2
2 from person p,table(p.address) p_add;
STREET_ADDRESS1 STREET_ADDRESS2
---------------------------------------- ----------------------------------------
123 main1
245 main1
Elapsed: 00:00:00.01
rajesh@10GR2>
rajesh@10GR2> update table (select address from person)
2 set street_address2 = street_address1;
set street_address2 = street_address1
*
ERROR at line 2:
ORA-25015: cannot perform DML on this nested table view column
Elapsed: 00:00:00.00
rajesh@10GR2> delete from table (select address from person);
delete from table (select address from person)
*
ERROR at line 1:
ORA-22906: cannot perform DML on expression or on nested table view column
Elapsed: 00:00:00.01
rajesh@10GR2>
Piece-wise updates of a varray value are not supported. Thus, when a varray is updated, the entire old collection is replaced by the new collection
- Nested tables will perform a relational JOIN to bring the collect back with the row. For small collections, this may be expensive
rajesh@10GR2> create type person_add as object(
2 street_address1 varchar2(40),
3 street_address2 varchar2(40),
4 city varchar2(40),
5 state varchar2(40),
6 zip number
7 );
8 /
Type created.
Elapsed: 00:00:00.10
rajesh@10GR2> create type person_typ_ntt is table of person_add;
2 /
Type created.
Elapsed: 00:00:00.06
rajesh@10GR2>
rajesh@10GR2> create table person_ntt(
2 person_id number,
3 first_name varchar2(30),
4 last_name varchar2(30),
5 address person_typ_ntt
6 )nested table address store as person_ntt_nest;
Table created.
Elapsed: 00:00:00.09
rajesh@10GR2>
rajesh@10GR2> insert into person_ntt
2 select object_id,object_name,object_name,person_typ_ntt(
3 person_add('123 main1',null,'CA','MN',123),
4 person_add('245 main1',null,'NJ','MN',245))
5 from all_objects;
56175 rows created.
Elapsed: 00:00:20.32
rajesh@10GR2> commit;
Commit complete.
Elapsed: 00:00:00.03
rajesh@10GR2> begin
2 dbms_stats.gather_table_stats(ownname=>user,tabname=>'PERSON_NTT',estimate_percent=>100,method_opt=>'for all columns size 254');
3 end;
4 /
PL/SQL procedure successfully completed.
Elapsed: 00:00:02.65
select p.person_id,p_add.street_address1,p_add.street_address2
from person_ntt p,table(p.address) p_add
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.01 0.31 0 1 0 0
Execute 1 0.00 0.02 0 0 0 0
Fetch 750 0.23 0.27 0 2007 0 112350
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 752 0.25 0.60 0 2008 0 112350
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 100
Rows Row Source Operation
------- ---------------------------------------------------
112350 HASH JOIN
(cr=2007 pr=0 pw=0 time=486462 us)
56175
TABLE ACCESS FULL PERSON_NTT (cr=581 pr=0 pw=0 time=71 us)
112350
TABLE ACCESS FULL PERSON_NTT_NEST (cr=1426 pr=0 pw=0 time=112409 us)
- VARRAYs do not join. The data is accessed inline for small collections, and as a LOB segment for large collections. In general, there will be less overhead associated with accessing a VARRAY compared to a nested table. There is potentially more overhead associated with updating a VARRAY as compared to a nested table however, since the entire VARRAY must be replaced ‐ not just an element of it.
rajesh@10GR2> create type person_varr is Varray(60000) of person_add;
2 /
Type created.
Elapsed: 00:00:00.07
rajesh@10GR2> create table person_varr_tab(
2 person_id number,
3 first_name varchar2(30),
4 last_name varchar2(30),
5 address person_varr
6 );
Table created.
Elapsed: 00:00:00.54
rajesh@10GR2>
rajesh@10GR2> insert into person_varr_tab
2 select object_id,object_name,object_name,person_varr(
3 person_add('123 main1',null,'CA','MN',123),
4 person_add('245 main1',null,'NJ','MN',245))
5 from all_objects;
56177 rows created.
Elapsed: 00:00:02.73
rajesh@10GR2> commit;
Commit complete.
Elapsed: 00:00:00.07
rajesh@10GR2> begin
2 dbms_stats.gather_table_stats(ownname=>user,tabname=>'PERSON_VARR_TAB',estimate_percent=>100,method_opt=>'for all columns size 254');
3 end;
4 /
PL/SQL procedure successfully completed.
Elapsed: 00:00:02.06
select p.person_id,p_add.street_address1,p_add.street_address2
from person_varr_tab p,table(p.address) p_add
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 751 0.95 0.79 0 1914 0 112354
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 753 0.95 0.79 0 1914 0 112354
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 100
Rows Row Source Operation
------- ---------------------------------------------------
112354 NESTED LOOPS (cr=1914 pr=0 pw=0 time=1011273 us)
56177
TABLE ACCESS FULL PERSON_VARR_TAB (cr=1914 pr=0 pw=0 time=112428 us)
112354 COLLECTION ITERATOR PICKLER FETCH (cr=0 pr=0 pw=0 time=275780 us)
- Nested tables are physically stored as a parent child table with surrogate keys.
test_user@10GR2> create type person_add as object(
2 street_address1 varchar2(40),
3 street_address2 varchar2(40),
4 city varchar2(40),
5 state varchar2(40),
6 zip number
7 );
8 /
Type created.
Elapsed: 00:00:00.10
test_user@10GR2> create type person_typ_ntt is table of person_add;
2 /
Type created.
Elapsed: 00:00:00.06
test_user@10GR2> create table person_ntt(
2 person_id number,
3 first_name varchar2(30),
4 last_name varchar2(30),
5 address person_typ_ntt
6 )nested table address store as person_ntt_nest;
Table created.
Elapsed: 00:00:00.15
test_user@10GR2>
test_user@10GR2>
test_user@10GR2> column obj# format 99999999;
test_user@10GR2> column col# format 99999;
test_user@10GR2> column name format a30;
test_user@10GR2>
test_user@10GR2> SELECT obj#, col#, name
2 FROM sys.col$
3 WHERE obj# IN
4 (SELECT object_id
5 FROM user_objects
6 WHERE object_name IN ('PERSON_NTT','PERSON_NTT_NEST'))
7 order by 1,2
8 /
OBJ# COL# NAME
--------- ------ ------------------------------
146579 1 PERSON_ID
146579 2 FIRST_NAME
146579 3 LAST_NAME
146579 4 ADDRESS
146579 4 SYS_NC0000400005$
146580 0 NESTED_TABLE_ID
146580 0 SYS_NC_ROWINFO$
146580 1 STREET_ADDRESS1
146580 2 STREET_ADDRESS2
146580 3 CITY
146580 4 STATE
146580 5 ZIP
12 rows selected.
Elapsed: 00:00:00.03
test_user@10GR2>
VARRAYs are stored as a RAW column or as a LOB. There is minimal overhead introduced for the functionality.
test_user@10GR2> create type person_add as object(
2 street_address1 varchar2(40),
3 street_address2 varchar2(40),
4 city varchar2(40),
5 state varchar2(40),
6 zip number
7 );
8 /
Type created.
Elapsed: 00:00:00.04
test_user@10GR2> create type person_varr is Varray(15) of person_add;
2 /
Type created.
Elapsed: 00:00:00.04
test_user@10GR2> create table PERSON_VARR_TAB(
2 person_id number,
3 first_name varchar2(30),
4 last_name varchar2(30),
5 address person_varr
6 );
Table created.
Elapsed: 00:00:00.04
test_user@10GR2>
test_user@10GR2> SELECT col#, name,length
2 FROM sys.col$
3 WHERE obj# =
4 (SELECT object_id
5 FROM user_objects
6 WHERE object_name = 'PERSON_VARR_TAB')
7 order by 1,2;
COL# NAME LENGTH
---------- ------------------------------ ----------
1 PERSON_ID 22
2 FIRST_NAME 30
3 LAST_NAME 30
4 ADDRESS 3002
Elapsed: 00:00:00.01
test_user@10GR2>
test_user@10GR2> Select object_type, object_name,
2 decode(status,'INVALID','*','') status,
3 tablespace_name
4 from user_objects a, user_segments b
5 where a.object_name = b.segment_name (+)
6 order by object_type, object_name;
OBJECT_TYPE OBJECT_NAME S TABLESPACE_NAME
------------------- ------------------------------ - ---------------------
TABLE PERSON_VARR_TAB USERS
TYPE PERSON_ADD
TYPE PERSON_VARR
Elapsed: 00:00:00.12
test_user@10GR2>
Oracle has added a 3000 byte column to support our VARRAY implementation. The data for our VARRAY will be stored inline (in the row itself). This raises an interesting question; what will happen if our array could exceed 4,000 bytes ?
test_user@10GR2> alter table PERSON_VARR_TAB drop column address;
Table altered.
Elapsed: 00:00:00.15
test_user@10GR2> create or replace type person_varr is Varray(25) of person_add;
2 /
Type created.
Elapsed: 00:00:00.14
test_user@10GR2> alter table person_varr_tab add address person_varr;
Table altered.
Elapsed: 00:00:00.06
test_user@10GR2>
test_user@10GR2> Select object_type, object_name,
2 decode(status,'INVALID','*','') status,
3 tablespace_name
4 from user_objects a, user_segments b
5 where a.object_name = b.segment_name (+)
6 order by object_type, object_name;
OBJECT_TYPE OBJECT_NAME S TABLESPACE_NAME
------------------- ------------------------------ - ------------------------------
LOB SYS_LOB0000146626C00004$$ USERS
TABLE PERSON_VARR_TAB USERS
TYPE PERSON_ADD
TYPE PERSON_VARR
Elapsed: 00:00:00.09
test_user@10GR2>
- Nested table ʹArrayʹ elements have no specific order. The data in the collection may be returned in a very different order than it was in when you inserted it.
rajesh@10GR2> create type too as object(
2 id number,
3 dt date,
4 data varchar2(20)
5 );
6 /
Type created.
Elapsed: 00:00:00.15
rajesh@10GR2> create type foo is table of too;
2 /
Type created.
Elapsed: 00:00:00.18
rajesh@10GR2>
rajesh@10GR2> create table t(
2 x number,
3 y foo)
4 nested table y store as t_y;
Table created.
Elapsed: 00:00:00.11
rajesh@10GR2>
rajesh@10GR2>
rajesh@10GR2> INSERT INTO t
2 (
3 x,
4 y
5 )
6 SELECT level ,
7 CAST(multiset
8 (SELECT too(level,sysdate,rpad('*',20,'*'))
9 FROM dual
10 CONNECT BY level <= 1000
11 ) AS foo)
12 FROM dual
13 CONNECT BY level <= 5;
5 rows created.
Elapsed: 00:00:00.07
rajesh@10GR2>
rajesh@10GR2> commit;
Commit complete.
Elapsed: 00:00:00.01
rajesh@10GR2>
rajesh@10GR2> SELECT x,
2 tab.id
3 FROM t ,
4 TABLE(t.y) tab
5 WHERE t.x = 2
6 AND rownum <= 5;
X ID
---------- ----------
2 191
2 192
2 193
2 194
2 195
Elapsed: 00:00:00.01
rajesh@10GR2>
rajesh@10GR2>
- VARRAYs are true arrays. The data will remain inherently ordered as you left it
rajesh@10GR2> create type too as object(
2 id number,
3 dt date,
4 data varchar2(20)
5 );
6 /
Type created.
Elapsed: 00:00:00.12
rajesh@10GR2> create type foo is Varray(1000) of too;
2 /
Type created.
Elapsed: 00:00:00.12
rajesh@10GR2>
rajesh@10GR2> create table t(
2 x number,
3 y foo);
Table created.
Elapsed: 00:00:00.09
rajesh@10GR2>
rajesh@10GR2> declare
2 l_foo foo;
3 begin
4 for k in 1..5
5 loop
6 l_foo := foo();
7 for i in 1..1000
8 loop
9 l_foo.extend;
10 l_foo(l_foo.last) := too(i,sysdate,rpad('*',20,'*'));
11 end loop;
12 insert into t values (k,l_foo);
13 end loop;
14 end;
15 /
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.07
rajesh@10GR2>
rajesh@10GR2>
rajesh@10GR2> commit;
Commit complete.
Elapsed: 00:00:00.04
rajesh@10GR2>
rajesh@10GR2> SELECT p.x,
2 t_tab.id
3 FROM t p,
4 TABLE(p.y) t_tab
5 where p.x = 2
6 and rownum <= 5;
X ID
---------- ----------
2 1
2 2
2 3
2 4
2 5
Elapsed: 00:00:00.00
rajesh@10GR2>
rajesh@10GR2>