You Asked
Hi Tom,
I have a table with following columns. One of the column is consider as nested table.
tb_users Datatype
-------------------------------
1. userid varchar2(15)
2. businessname varchar2(50)
3. userprivileges ourprivileges
( Nested table column having type of privilegetype (privilege_id number(2),privilege_name varchar2(45))
Initially we have assigned some set of application privilege to the user..
Now i wanted to find user with privilege_id = 2
select userid, b.privilege_id from tb_users , table(userprivileges) b
where b.privilege_id = 2
I got the expected output.. we want to delete this privilege from all the user.
i want to delete the nested table record with privilege_id = 2(child table) for all the user
I can delete privilege of one particular user using following query.
delete from the ( select userprivileges from tb_users where
userid ='sathya') where privilege_id = 2
How to do it for all the user with single query.. Instead of writing procedure with cursor to do the same.
Thanks in Advance.
Regards,
Sathiamathi
create table tb_users (userid varchar2(15),privileges
userid
and Tom said...
Ahh, the foibles of nested tables! This is (in my opinion) one of the issues with "OO" approaches here.
You want to have this nice representation as an object -- yet we constantly need a relational view of the data to get the job done.
My favorite example is a "bank". The application for the teller would like to have an object that represents the customer. They see the customer, with a list of accounts that have lists of transactions. Very nice for the teller. However at the end of the day, someone asks "how much money is in the bank"? Well, now we need a totally different view of the data -- from the perspective of transactions, not people (you don't want to go to each person object and say "did you do anything today?" that would not be realistic, you just want to sum up transactions)....
This is a small extract from my book that describes this issue and offers a solution for ONE OFF fixes (all of the details are in the book)
....
Previously I stated: 'We must always join, we cannot query the EMP data alone' but then 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, we would have to do that through the DEPT table with a join). There is an undocumented hint, NESTED_TABLE_GET_REFS, used by EXP and IMP to deal with nested tables. It will also be a way to see a little more about the physical structure of the nested tables. This magic hint is easy to discover after you export a table with a nested table. For example, I exported the table above in order to get its 'larger' definition from IMP. After doing the export, I found the following SQL in my shared pool (V$SQL table):
SELECT /*+NESTED_TABLE_GET_REFS+*/ NESTED_TABLE_ID,SYS_NC_ROWINFO$ FROM "TKYTE"."EMPS_NT"
A simple query like 'select sql_text from v$sql where upper(sql_text) like ?%EMP%' found it for me. If you run this, you'll get some 'magic' results:
tkyte@TKYTE816> SELECT /*+NESTED_TABLE_GET_REFS+*/
2 NESTED_TABLE_ID,SYS_NC_ROWINFO$
3 FROM "TKYTE"."EMPS_NT"
4 /
NESTED_TABLE_ID SYS_NC_ROWINFO$(EMPNO, ENAME,
-------------------------------- ------------------------------
9A39835005B149859735617476C9A80E EMP_TYPE(7782, 'CLARK',
'MANAGER', 7839, '09-JUN-81',
2450, 100)
9A39835005B149859735617476C9A80E EMP_TYPE(7839, 'KING',
'PRESIDENT', NULL,
'17-NOV-81', 5000, 100)
Well, this is somewhat surprising, if you describe this table:
tkyte@TKYTE816> desc emps_nt
Name Null? Type
----------------------------------- -------- ------------------------
EMPNO NUMBER(4)
ENAME VARCHAR2(10)
JOB VARCHAR2(9)
MGR NUMBER(4)
HIREDATE DATE
SAL NUMBER(7,2)
COMM NUMBER(7,2)
These two columns don?t even show up. They are part of the hidden implementation of nested tables. The NESTED_TABLE_ID is really a foreign key to the parent table DEPT_AND_EMP. DEPT_AND_EMP actually has a hidden column in it that is used to join to EMPS_NT. The SYS_NC_ROWINF$ 'column' is a magic column, it is more of a function then a column. The nested table here is really an object table (it is made of an object type) and SYS_NC_INFO$ is the internal way Oracle references the row as an object, instead of referencing each of the scalar columns. Under the covers, all Oracle has done for us is to implement a parent/child table with system generated primary and foreign keys. If we dig a little further, we can query the 'real' data dictionary to see all of the columns in the DEPT_AND_EMP table:
tkyte@TKYTE816> select name
2 from sys.col$
3 where obj# = ( select object_id
4 from user_objects
5 where object_name = 'DEPT_AND_EMP' )
6 /
NAME
------------------------------
DEPTNO
DNAME
LOC
EMPS
SYS_NC0000400005$
tkyte@TKYTE816> select SYS_NC0000400005$ from dept_and_emp;
SYS_NC0000400005$
--------------------------------
9A39835005B149859735617476C9A80E
A7140089B1954B39B73347EC20190D68
20D4AA0839FB49B0975FBDE367842E16
56350C866BA24ADE8CF9E47073C52296
The weird looking column name, SYS_NC0000400005$, is the system-generated key placed into the DEPT_AND_EMP table. If you dig even further you will find that Oracle has placed a unique index on this column. Unfortunately however, it neglected to index the NESTED_TABLE_ID in EMPS_NT. This column really needs to be indexed, as we are always joining FROM DEPT_AND_EMP to EMPS_NT. This is an important thing to remember about nested tables if you use them with all of the defaults as I did above ? always index the NESTED_TABLE_ID in the nested tables!
I've gotten off of the track though at this point. I was talking about how to treat the nested table as if it were a real table. The NESTED_TABLE_GET_REFS hint does that for us. We can use that like this:
tkyte@TKYTE816> select /*+ nested_table_get_refs */ empno, ename
2 from emps_nt where ename like '%A%';
EMPNO ENAME
---------- ----------
7782 CLARK
7876 ADAMS
7499 ALLEN
7521 WARD
7654 MARTIN
7698 BLAKE
7900 JAMES
7 rows selected.
tkyte@TKYTE816> update /*+ nested_table_get_refs */ emps_nt
2 set ename = initcap(ename);
14 rows updated.
tkyte@TKYTE816> select /*+ nested_table_get_refs */ empno, ename
2 from emps_nt where ename like '%a%';
EMPNO ENAME
---------- ----------
7782 Clark
7876 Adams
7521 Ward
7654 Martin
7698 Blake
7900 James
6 rows selected.
Again, this is not a documented supported feature. It may not work in all environments. 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. Use it with caution though and do not put it into production code. 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 unnest it like this:
tkyte@TKYTE816> select d.deptno, d.dname, emp.*
2 from dept_and_emp D, table(d.emps) emp
3 /
And that is what you should use in queries and production code.
....
Rating
(15 ratings)
Is this answer out of date? If it is, please let us know via a Comment