Apress.Expert.Oracle.Database.Architecture.9i.and.10g.Programming.Techniques.and.Solutions.Sep.2005

rekharaghuram
from rekharaghuram More from this publisher
05.11.2015 Views

CHAPTER 10 ■ DATABASE TABLES 395 5 ) 6 set comm = 100 7 / update * ERROR at line 1: ORA-22908: reference to NULL table value ops$tkyte@ORA10G> update 2 table( select emps 3 from dept_and_emp 4 where deptno > 1 5 ) 6 set comm = 100 7 / table( select emps * ERROR at line 2: ORA-01427: single-row subquery returns more than one row If we return fewer than one row (one nested table instance), the update fails. Normally an update of zero rows is OK, but not in this case—it returns an error the same as if we left the table name off the update. If we return more than one row (more than one nested table instance), the update fails. Normally an update of many rows is perfectly OK. This shows that Oracle considers each row in the DEPT_AND_EMP table to point to another table, not just another set of rows as the relational model does. This is the semantic difference between a nested table and a parent/child relational table. In the nested table model, there is one table per parent row. In the relational model, there is one set of rows per parent row. This difference can make nested tables somewhat cumbersome to use at times. Consider this model we are using, which provides a very nice view of the data from the perspective of single department. It is a terrible model if we want to ask questions like “What department does KING work for?”, “How many accountants do we have working for us?”, and so on. These questions are best asked of the EMP relational table, but in this nested table model we can only access the EMP data via the DEPT data. We must always join; we cannot query the EMP data alone. Well, we can’t do it in a supported, documented method, but we can use a trick (more on this trick later). If we needed to update every row in the EMPS_NT, we would have to do four updates: one each for the rows in DEPT_AND_EMP to update the virtual table associated with each row. Another thing to consider is that when we updated the employee data for department 10, we were semantically updating the EMPS column in the DEPT_AND_EMP table. We understand that physically there are two tables involved, but semantically there is only one. Even though we updated no data in the department table, the row that contains the nested table we did modify is locked from update by other sessions. In a traditional parent/child table relationship, this would not be the case. These are the reasons why I tend to stay away from nested tables as a persistent storage mechanism. It is the rare child table that is not queried stand-alone. In the preceding example,

396 CHAPTER 10 ■ DATABASE TABLES the EMP table should be a strong entity. It stands alone, so it needs to be queried alone. I find this to be the case almost all of the time. I tend to use nested tables via views on relational tables. So, now that we have seen how to update a nested table instance, inserting and deleting are pretty straightforward. Let’s add a row to the nested table instance department 10 and remove a row from department 20: ops$tkyte@ORA10G> insert into table 2 ( select emps from dept_and_emp where deptno = 10 ) 3 values 4 ( 1234, 'NewEmp', 'CLERK', 7782, sysdate, 1200, null ); 1 row created. ops$tkyte@ORA10G> delete from table 2 ( select emps from dept_and_emp where deptno = 20 ) 3 where ename = 'SCOTT'; 1 row deleted. ops$tkyte@ORA10G> select d.dname, e.empno, ename 2 from dept_and_emp d, table(d.emps) e 3 where d.deptno in ( 10, 20 ); DNAME EMPNO ENAME -------------- ---------- ---------- ACCOUNTING 7782 CLARK ACCOUNTING 7839 KING ACCOUNTING 7934 MILLER RESEARCH 7369 SMITH RESEARCH 7566 JONES RESEARCH 7876 ADAMS RESEARCH 7902 FORD ACCOUNTING 1234 NewEmp 8 rows selected. That is the basic syntax of how to query and modify nested tables. You will find many times that you must un-nest these tables as we just did, especially in queries, to make use of them. Once you conceptually visualize the “virtual table per row” concept, working with nested tables becomes much easier. Previously I stated, “We must always join; we cannot query the EMP data alone,” but then I followed that up with a caveat: “You can if you really need to.” It is undocumented and not supported, so use it only as a last ditch method. Where it will come in most handy is if you ever need to mass update the nested table (remember, you would have to do that through the DEPT table with a join). There is an underdocumented hint (it is mentioned briefly and not fully documented), NESTED_TABLE_GET_REFS, which is used by various tools such as EXP and IMP to deal with nested tables. It is also a way to see a little more about the physical structure of the nested tables. If you use this hint, you can query to get some “magic” results. The following query is what EXP (a data unload utility) uses to extract the data from this nested table:

396<br />

CHAPTER 10 ■ DATABASE TABLES<br />

the EMP table should be a strong entity. It st<strong>and</strong>s alone, so it needs to be queried alone. I find<br />

this to be the case almost all of the time. I tend to use nested tables via views on relational<br />

tables.<br />

So, now that we have seen how to update a nested table instance, inserting <strong>and</strong> deleting<br />

are pretty straightforward. Let’s add a row to the nested table instance department 10 <strong>and</strong><br />

remove a row from department 20:<br />

ops$tkyte@ORA10G> insert into table<br />

2 ( select emps from dept_<strong>and</strong>_emp where deptno = 10 )<br />

3 values<br />

4 ( 1234, 'NewEmp', 'CLERK', 7782, sysdate, 1200, null );<br />

1 row created.<br />

ops$tkyte@ORA10G> delete from table<br />

2 ( select emps from dept_<strong>and</strong>_emp where deptno = 20 )<br />

3 where ename = 'SCOTT';<br />

1 row deleted.<br />

ops$tkyte@ORA10G> select d.dname, e.empno, ename<br />

2 from dept_<strong>and</strong>_emp d, table(d.emps) e<br />

3 where d.deptno in ( 10, 20 );<br />

DNAME<br />

EMPNO ENAME<br />

-------------- ---------- ----------<br />

ACCOUNTING<br />

7782 CLARK<br />

ACCOUNTING<br />

7839 KING<br />

ACCOUNTING<br />

7934 MILLER<br />

RESEARCH<br />

7369 SMITH<br />

RESEARCH<br />

7566 JONES<br />

RESEARCH<br />

7876 ADAMS<br />

RESEARCH<br />

7902 FORD<br />

ACCOUNTING<br />

1234 NewEmp<br />

8 rows selected.<br />

That is the basic syntax of how to query <strong>and</strong> modify nested tables. You will find many<br />

times that you must un-nest these tables as we just did, especially in queries, to make use of<br />

them. Once you conceptually visualize the “virtual table per row” concept, working with<br />

nested tables becomes much easier.<br />

Previously I stated, “We must always join; we cannot query the EMP data alone,” but then<br />

I followed that up with a caveat: “You can if you really need to.” It is undocumented <strong>and</strong> not<br />

supported, so use it only as a last ditch method. Where it will come in most h<strong>and</strong>y is if you ever<br />

need to mass update the nested table (remember, you would have to do that through the DEPT<br />

table with a join). There is an underdocumented hint (it is mentioned briefly <strong>and</strong> not fully<br />

documented), NESTED_TABLE_GET_REFS, which is used by various tools such as EXP <strong>and</strong> IMP to<br />

deal with nested tables. It is also a way to see a little more about the physical structure of the<br />

nested tables. If you use this hint, you can query to get some “magic” results. The following<br />

query is what EXP (a data unload utility) uses to extract the data from this nested table:

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!