Apress.Expert.Oracle.Database.Architecture.9i.and.10g.Programming.Techniques.and.Solutions.Sep.2005
CHAPTER 10 ■ DATABASE TABLES 399 EMPNO ENAME ---------- ---------- 7782 Clark 7876 Adams 7521 Ward 7654 Martin 7698 Blake 7900 James 6 rows selected. Again, this is not a thoroughly documented and supported feature. It has a specific functionality for EXP and IMP to work. This is the only environment it is assured to work in. Use it at your own risk, and resist putting it into production code. In fact, if you find you need to use it, then by definition you didn’t mean to use a nested table at all! It is the wrong construct for you. Use it for one-off fixes of data or to see what is in the nested table out of curiosity. The supported way to report on the data is to un-nest it like this: ops$tkyte@ORA10G> select d.deptno, d.dname, emp.* 2 from dept_and_emp D, table(d.emps) emp 3 / This is what you should use in queries and production code. Nested Table Storage We have already seen some of the storage of the nested table structure. In this section, we’ll take an in-depth look at the structure created by Oracle by default and what sort of control over that we have. Working with the same CREATE statement as before ops$tkyte@ORA10G> create table dept_and_emp 2 (deptno number(2) primary key, 3 dname varchar2(14), 4 loc varchar2(13), 5 emps emp_tab_type 6 ) 7 nested table emps store as emps_nt; Table created. ops$tkyte@ORA10G> alter table emps_nt add constraint emps_empno_unique 2 unique(empno) 3 / Table altered. we know that Oracle really creates a structure like the one shown in Figure 10-11.
400 CHAPTER 10 ■ DATABASE TABLES Figure 10-11. Nested table physical implementation The code created two real tables. The table we asked to have is there, but it has an extra hidden column (we’ll have one extra hidden column by default for each nested table column in a table). It also created a unique constraint on this hidden column. Oracle created the nested table, EMPS_NT, for us. This table has two hidden columns, one of which, SYS_NC_ ROWINFO$, is not really a column but a virtual column that returns all of the scalar elements as an object. The other is the foreign key called NESTED_TABLE_ID, which can be joined back to the parent table. Notice the lack of an index on this column. Finally, Oracle added an index on the DEPTNO column in the DEPT_AND_EMP table to enforce the primary key. So, we asked for a table and got a lot more than we bargained for. If you look at it, it is a lot like what you might create for a parent/child relationship, but you would have used the existing primary key on DEPTNO as the foreign key in EMPS_NT instead of generating a surrogate RAW(16) key. If we look at the DBMS_METADATA.GET_DDL dump of our nested table example, we see the following: ops$tkyte@ORA10G> begin 2 dbms_metadata.set_transform_param 3 ( DBMS_METADATA.SESSION_TRANSFORM, 'STORAGE', false ); 4 end; 5 / PL/SQL procedure successfully completed. ops$tkyte@ORA10G> select dbms_metadata.get_ddl( 'TABLE', 'DEPT_AND_EMP' ) from dual; DBMS_METADATA.GET_DDL('TABLE','DEPT_AND_EMP') ------------------------------------------------------------------------------- CREATE TABLE "OPS$TKYTE"."DEPT_AND_EMP" ( "DEPTNO" NUMBER(2,0),
- Page 393 and 394: 348 CHAPTER 10 ■ DATABASE TABLES
- Page 395 and 396: 350 CHAPTER 10 ■ DATABASE TABLES
- Page 397 and 398: 352 CHAPTER 10 ■ DATABASE TABLES
- Page 399 and 400: 354 CHAPTER 10 ■ DATABASE TABLES
- Page 401 and 402: 356 CHAPTER 10 ■ DATABASE TABLES
- Page 403 and 404: 358 CHAPTER 10 ■ DATABASE TABLES
- Page 405 and 406: 360 CHAPTER 10 ■ DATABASE TABLES
- Page 407 and 408: 362 CHAPTER 10 ■ DATABASE TABLES
- Page 409 and 410: 364 CHAPTER 10 ■ DATABASE TABLES
- Page 411 and 412: 366 CHAPTER 10 ■ DATABASE TABLES
- Page 413 and 414: 368 CHAPTER 10 ■ DATABASE TABLES
- Page 415 and 416: 370 CHAPTER 10 ■ DATABASE TABLES
- Page 417 and 418: 372 CHAPTER 10 ■ DATABASE TABLES
- Page 419 and 420: 374 CHAPTER 10 ■ DATABASE TABLES
- Page 421 and 422: 376 CHAPTER 10 ■ DATABASE TABLES
- Page 423 and 424: 378 CHAPTER 10 ■ DATABASE TABLES
- Page 425 and 426: 380 CHAPTER 10 ■ DATABASE TABLES
- Page 427 and 428: 382 CHAPTER 10 ■ DATABASE TABLES
- Page 429 and 430: 384 CHAPTER 10 ■ DATABASE TABLES
- Page 431 and 432: 386 CHAPTER 10 ■ DATABASE TABLES
- Page 433 and 434: 388 CHAPTER 10 ■ DATABASE TABLES
- Page 435 and 436: 390 CHAPTER 10 ■ DATABASE TABLES
- Page 437 and 438: 392 CHAPTER 10 ■ DATABASE TABLES
- Page 439 and 440: 394 CHAPTER 10 ■ DATABASE TABLES
- Page 441 and 442: 396 CHAPTER 10 ■ DATABASE TABLES
- Page 443: 398 CHAPTER 10 ■ DATABASE TABLES
- Page 447 and 448: 402 CHAPTER 10 ■ DATABASE TABLES
- Page 449 and 450: 404 CHAPTER 10 ■ DATABASE TABLES
- Page 451 and 452: 406 CHAPTER 10 ■ DATABASE TABLES
- Page 453 and 454: 408 CHAPTER 10 ■ DATABASE TABLES
- Page 455 and 456: 410 CHAPTER 10 ■ DATABASE TABLES
- Page 457 and 458: 412 CHAPTER 10 ■ DATABASE TABLES
- Page 459 and 460: 414 CHAPTER 10 ■ DATABASE TABLES
- Page 461 and 462: 416 CHAPTER 10 ■ DATABASE TABLES
- Page 463 and 464: 418 CHAPTER 10 ■ DATABASE TABLES
- Page 466 and 467: CHAPTER 11 ■ ■ ■ Indexes Inde
- Page 468 and 469: CHAPTER 11 ■ INDEXES 423 value of
- Page 470 and 471: CHAPTER 11 ■ INDEXES 425 One of t
- Page 472 and 473: CHAPTER 11 ■ INDEXES 427 We then
- Page 474 and 475: CHAPTER 11 ■ INDEXES 429 we ended
- Page 476 and 477: CHAPTER 11 ■ INDEXES 431 The data
- Page 478 and 479: CHAPTER 11 ■ INDEXES 433 if ( (++
- Page 480 and 481: CHAPTER 11 ■ INDEXES 435 Table 11
- Page 482 and 483: CHAPTER 11 ■ INDEXES 437 When Sho
- Page 484 and 485: CHAPTER 11 ■ INDEXES 439 an 8KB b
- Page 486 and 487: CHAPTER 11 ■ INDEXES 441 select *
- Page 488 and 489: CHAPTER 11 ■ INDEXES 443 select *
- Page 490 and 491: CHAPTER 11 ■ INDEXES 445 Indicate
- Page 492 and 493: CHAPTER 11 ■ INDEXES 447 an index
CHAPTER 10 ■ DATABASE TABLES 399<br />
EMPNO ENAME<br />
---------- ----------<br />
7782 Clark<br />
7876 Adams<br />
7521 Ward<br />
7654 Martin<br />
7698 Blake<br />
7900 James<br />
6 rows selected.<br />
Again, this is not a thoroughly documented <strong>and</strong> supported feature. It has a specific functionality<br />
for EXP <strong>and</strong> IMP to work. This is the only environment it is assured to work in. Use it at<br />
your own risk, <strong>and</strong> resist putting it into production code. In fact, if you find you need to use it,<br />
then by definition you didn’t mean to use a nested table at all! It is the wrong construct for<br />
you. Use it for one-off fixes of data or to see what is in the nested table out of curiosity. The<br />
supported way to report on the data is to un-nest it like this:<br />
ops$tkyte@ORA10G> select d.deptno, d.dname, emp.*<br />
2 from dept_<strong>and</strong>_emp D, table(d.emps) emp<br />
3 /<br />
This is what you should use in queries <strong>and</strong> production code.<br />
Nested Table Storage<br />
We have already seen some of the storage of the nested table structure. In this section, we’ll<br />
take an in-depth look at the structure created by <strong>Oracle</strong> by default <strong>and</strong> what sort of control<br />
over that we have. Working with the same CREATE statement as before<br />
ops$tkyte@ORA10G> create table dept_<strong>and</strong>_emp<br />
2 (deptno number(2) primary key,<br />
3 dname varchar2(14),<br />
4 loc varchar2(13),<br />
5 emps emp_tab_type<br />
6 )<br />
7 nested table emps store as emps_nt;<br />
Table created.<br />
ops$tkyte@ORA10G> alter table emps_nt add constraint emps_empno_unique<br />
2 unique(empno)<br />
3 /<br />
Table altered.<br />
we know that <strong>Oracle</strong> really creates a structure like the one shown in Figure 10-11.