Rem Rem Copyright (c) 1998 By Oracle Corporation Rem Rem NAME Rem tabdemo.sql - Demo Program For Table Operator Rem Rem The demo program does the following tasks : Rem Rem 1) Shows unnesting of nested tables using TABLE operator. Rem Rem 2) Shows converting a local PL/SQL collection variable into a relational Rem table using TABLE operator. Rem Rem Rem FUNCTION Rem Rem The demo program illustrates the use of TABLE operator for unnesting Rem collections as well as converting a local PL/SQL collection variable Rem into a relational table. Rem Rem Unnesting here refers to iterating over all collection values of Rem collection column of a table. Rem In Pre 8.1, unnesting can be done using local PL/SQL variables and Rem cursors but this process is quite cumbersome. Rem Rem TABLE operator in RDBMS 8.1 allows us to unnest collection columns Rem easily as well as convert local PL/SQL collection variables into Rem relational tables. Rem Rem NOTES ON EXECUTING THIS DEMO PROGRAM Rem Rem 1) Use svrmgrl for running this demo program Rem Rem 2) Connect as SCOTT/TIGER and run tabdemo.sql Rem Rem CONNECT SCOTT/TIGER Rem @tabdemo.sql Rem Rem Rem MODIFIED Rem gviswana 09/30/98 - Add to demo directory Rem ukulkarn.in 08/27/98 - Creation /* ** ########################################################################## ** ** DESCRIPTION OF DEMO EXAMPLE ** ** ########################################################################## ** ** In the Demo example, there is one module namely proj_emp_track module. ** ** This module keeps track of the following information for all departments in ** an organization. ** ** 1) Current projects being executed. ** 2) Details of current employees. ** 3) Which employee is working on which project ** ** Frequently there is a need to query the above information to form different ** reports required by the Middle and Top Management. ** ** The module proj_emp_track module gives functionality to answer queries of ** above mentioned type and prepare different reports. ** ** In this demo example, the table dept_info (Described in details in following ** sections) has two columns namely ** a) Projects :- For storing projects related information ** b) Employee :- For Storing Employees related information ** ** These two columns are of collection(table) type and hence dept_info table ** becomes a nested table. ** ** Frequently asked queries/reports, For Example ** 'List all projects currently handled by all departments ' ** require to iterate over all collection values of collection column(s). ** ** Using TABLE operator this can be done very easily as demonstrated in ** the demo example. ** ** 1) Each project information is captured as an object 'project' with ** following attributes : ** ** a) Project_Id VARCHAR2(10) # Project Id # ** b) Project_name VARCHAR2(20) # Name # ** c) Budget NUMBER(10,2) # Budget # ** ** 2) Each employee currently works on a single project and no employee can ** work on two different projects at the same time. ** ** 3) Each Employee information is captured as an object 'employee' with the ** following attributes : ** ** a) Employee_Id VARCHAR2(10) # Employee Id # ** b) Employee_Name VARCHAR2(30) # Name # ** c) Current_Project_id VARCHAR2(10) # Current project on which ** ** 4) To record all projects currently being carried out in the organization ** a nested table type of 'project' object is created. ** ** Create Type nt_project as table of project; ** ** 5) To record employee information for all employees in the organization ** a nested table type of 'employee' is created. ** ** 6) To record department wise information which includes current projects ** carried in the department and the employees working on those projects, ** a table dept_info is created. ** ** Create Table Dept_info ( ** Dept_no VARCHAR2(10), ** Dept_Name VARCHAR2(20), ** Dept_Location VARCHAR2(20), ** Projects nt_project, ** Employees nt_employee ) Nested table Projects Store as p_j, ** Nested Table Employees Store as e_j; ** */ /* ** ######################################################################### ** ** CODING STYLE USED ** ** ########################################################################## ** ** 1.Uppercase is used for PL/SQL keywords and lower case for defined items. ** ** 2. Naming convention followed for user defined types : ** ------------------------------------------------------------------ ** Data Structure Name Prefixed with ** ----------------------------------------------------------------- ** Nested Table Types nt_ ** Object Types ot_ ** Local Variables l_ ** Reference Cursor rc_ ** */ CONNECT SCOTT/TIGER; SET ECHO ON; SET SERVEROUTPUT ON; SPOOL tabdemo.dbg /* -------------------------------------------------------------------- */ /* Define Object Type for storing project related information */ /* -------------------------------------------------------------------- */ CREATE TYPE ot_project AS OBJECT ( Project_Id VARCHAR2(10), Project_Name VARCHAR2(20), Budget NUMBER(10,2) ); / SHOW ERRORS /* -------------------------------------------------------------------- */ /* Define Object Type for storing employee related information */ /* -------------------------------------------------------------------- */ CREATE TYPE ot_employee AS OBJECT ( Emp_id VARCHAR2(10), Emp_name VARCHAR2(40), Current_Proj_Id VARCHAR2(10), Sal NUMBER(8,2) ) / SHOW ERRORS /* -------------------------------------------------------------------- */ /* Define Nested Table Type of ot_project object type */ /* -------------------------------------------------------------------- */ CREATE TYPE nt_project AS TABLE OF ot_project; / /* -------------------------------------------------------------------- */ /* Define Nested Table Type of ot_employee object type */ /* -------------------------------------------------------------------- */ CREATE TYPE nt_employee AS TABLE OF ot_employee; / /* -------------------------------------------------------------------- */ /* Define Object Type for Storing Project Name and Employee Name */ /* -------------------------------------------------------------------- */ CREATE TYPE ot_proj_emp AS OBJECT ( proj_name VARCHAR2(20), emp_name VARCHAR2(40) ); / /* -------------------------------------------------------------------- */ /* Define Nested Table Type of ot_proj_emp object type */ /* -------------------------------------------------------------------- */ CREATE TYPE nt_projemp AS TABLE OF ot_proj_emp; / /* -------------------------------------------------------------------- */ /* Table for storing Department related information */ /* -------------------------------------------------------------------- */ CREATE TABLE dept_info( dept_no VARCHAR2(10), dept_name VARCHAR2(50), projects nt_project, dept_loc VARCHAR2(30), employees nt_employee) NESTED TABLE projects STORE AS p_j, NESTED TABLE employees STORE AS e_m; / SHOW ERRORS /* -------------------------------------------------------------------- */ /* Define Nested Table Type for local processing */ /* -------------------------------------------------------------------- */ CREATE TYPE nt_chr50 AS TABLE OF VARCHAR2(50); / /* -------------------------------------------------------------------- */ /* Define Nested Table Type for local processing */ /* -------------------------------------------------------------------- */ CREATE TYPE nt_chr20 AS TABLE OF VARCHAR2(20); / /* -------------------------------------------------------------------- */ /* Define Nested Table Type for local processing */ /* -------------------------------------------------------------------- */ CREATE TYPE nt_chr10 AS TABLE OF VARCHAR2(10); / /* -------------------------------------------------------------------- */ /* Define Nested Table Type for local processing */ /* -------------------------------------------------------------------- */ CREATE TYPE nt_num102 AS TABLE OF NUMBER(10,2); / /* -------------------------------------------------------------------- */ /* Define Nested Table Type for local processing */ /* -------------------------------------------------------------------- */ CREATE TYPE nt_chr40 AS TABLE OF VARCHAR2(40); / /* -------------------------------------------------------------------- */ /* Define Nested Table Type for local processing */ /* -------------------------------------------------------------------- */ CREATE TYPE nt_num82 AS TABLE OF NUMBER(8,2); / /* ----------------------------------------------------------------------- */ /* Declaring a package specification where procedures for querying */ /* department wise project information and employee information resides. */ /* The package defines following procedures */ /* 1) Display_dept_projs - Display Department Wise Project Info */ /* 2) Display_dept_emp - Display Department Wise Employee Info */ /* 3) Display_proj_emp - Display Employee and Corresponding Project */ /* The package defines a function get_emp_proj which expects two parameters*/ /* a) Nested table of Project related information */ /* b) Nested table of Employee related information */ /* The function returns nested table of ot_emp_proj object which tells */ /* who is working on which project. */ /* ----------------------------------------------------------------------- */ CREATE OR REPLACE PACKAGE proj_emp_pack AS PROCEDURE display_dept_projs; PROCEDURE display_dept_emp; PROCEDURE display_proj_emp; FUNCTION get_emp_proj(p1 nt_project, p2 nt_employee) RETURN nt_projemp; PRAGMA RESTRICT_REFERENCES(get_emp_proj,RNDS,WNDS,RNPS,WNPS); END proj_emp_pack; / SHOW ERRORS /* ----------------------------------------------------------------------- */ /* Define Body of the package. */ /* ----------------------------------------------------------------------- */ CREATE OR REPLACE PACKAGE BODY proj_emp_pack AS /* -------------------------------------------------------------------- */ /* Procedure to display Department Names and the current Projects */ /* being executed currently by the department. */ /* -------------------------------------------------------------------- */ PROCEDURE display_dept_projs IS -- Define weakly typed reference cursor TYPE rc_c IS REF CURSOR; l_c1 rc_c; l_v1 nt_chr50 := nt_chr50(NULL); l_v2 nt_chr10 := nt_chr10(NULL); l_v3 nt_chr20 := nt_chr20(NULL); l_v4 nt_num102 := nt_num102(NULL); l_i NUMBER := 1; l_total_projects NUMBER := 0; BEGIN -- Using TABLE Operator to unnest projects column of dept_info table OPEN l_c1 FOR 'SELECT p1.dept_name,p2.* FROM dept_info p1, TABLE(p1.projects)p2'; LOOP FETCH l_c1 INTO l_v1(l_i),l_v2(l_i),l_v3(l_i),l_v4(l_i); EXIT WHEN l_c1%NOTFOUND; l_v1.EXTEND; l_v2.EXTEND; l_v3.EXTEND; l_v4.EXTEND; l_i := l_i + 1; END LOOP; CLOSE l_c1; l_v1.TRIM; l_v2.TRIM; l_v3.TRIM; l_v4.TRIM; -- Demonstrating converting local PL/SQL collection variable into a -- relational table. SELECT COUNT(*) INTO l_total_projects FROM TABLE(CAST(l_v2 as nt_chr10)); -- Displaying the Department Name and Corresponding Project Info DBMS_OUTPUT.PUT_LINE(' Listing Of Department Wise Current Projects :'); DBMS_OUTPUT.NEW_LINE(); DBMS_OUTPUT.PUT_LINE('--------------------------------------------' || '----------------'); DBMS_OUTPUT.PUT_LINE(' Department Project Id Project Name '|| ' Budget($)'); DBMS_OUTPUT.PUT_LINE('--------------------------------------------' || '----------------'); FOR l_i IN 1..l_v1.COUNT LOOP DBMS_OUTPUT.PUT_LINE(l_v1(l_i)||' '||l_v2(l_i)||' '|| l_v3(l_i)||' '|| l_v4(l_i)); END LOOP; DBMS_OUTPUT.PUT_LINE('--------------------------------------------' || '----------------'); DBMS_OUTPUT.NEW_LINE(); DBMS_OUTPUT.PUT_LINE('** Total Number Of Projects ---> '|| l_total_projects); END display_dept_projs; /* -------------------------------------------------------------------- */ /* Procedure to display Department Names and the current Employees */ /* employed by the department. */ /* -------------------------------------------------------------------- */ PROCEDURE display_dept_emp IS -- Define weakly typed reference cursor TYPE rc_c1 IS REF CURSOR; l_c1 rc_c1; l_v1 nt_chr10 := nt_chr10(NULL); l_v3 nt_chr50 := nt_chr50(NULL); l_v5 nt_chr40 := nt_chr40(NULL); l_v6 nt_chr10 := nt_chr10(NULL); l_v7 nt_num82 := nt_num82(NULL); l_i NUMBER := 1; l_total_employees NUMBER := 0; BEGIN -- Using TABLE Operator to unnest employees column of dept_info table OPEN l_c1 FOR 'SELECT p1.dept_name, p3.* FROM dept_info p1, TABLE(p1.employees) p3'; LOOP FETCH l_c1 INTO l_v3(l_i),l_v1(l_i),l_v5(l_i),l_v6(l_i),l_v7(l_i); EXIT WHEN l_c1%NOTFOUND; l_v1.EXTEND; l_v3.EXTEND; l_v5.EXTEND; l_v6.EXTEND; l_v7.EXTEND; l_i := l_i + 1; END LOOP; CLOSE l_c1; l_v1.TRIM; l_v3.TRIM; l_v5.TRIM; l_v6.TRIM; l_v7.TRIM; -- Demonstrating converting local PL/SQL collection variable into a -- relational table. SELECT COUNT(*) INTO l_total_employees FROM TABLE(CAST(l_v1 as nt_chr10)); -- Displaying the Department Name and Corresponding Employee Info DBMS_OUTPUT.NEW_LINE(); DBMS_OUTPUT.NEW_LINE(); DBMS_OUTPUT.PUT_LINE(' Listing Of Department Wise Current Employees : '); DBMS_OUTPUT.NEW_LINE(); DBMS_OUTPUT.PUT_LINE('--------------------------------------------' || '----------------'); DBMS_OUTPUT.PUT_LINE(' Department Employee Name Project '|| ' Salary($)'); DBMS_OUTPUT.PUT_LINE('--------------------------------------------' || '----------------'); FOR l_i IN 1..l_v1.COUNT LOOP DBMS_OUTPUT.PUT_LINE(l_v3(l_i)||' '||l_v5(l_i)||' '|| l_v6(l_i)|| ' '|| l_v7(l_i)); END LOOP; DBMS_OUTPUT.PUT_LINE('--------------------------------------------' || '----------------'); DBMS_OUTPUT.NEW_LINE(); DBMS_OUTPUT.PUT_LINE('** Total Number Of Employees ---> '|| l_total_employees); DBMS_OUTPUT.NEW_LINE(); END display_dept_emp; /* -------------------------------------------------------------------- */ /* Procedure to display Employee Names and the current Project on */ /* which the employee is working. */ /* -------------------------------------------------------------------- */ PROCEDURE display_proj_emp IS TYPE rc_c1 IS REF CURSOR; l_c1 rc_c1; l_v2 nt_chr20 := nt_chr20(NULL); l_v3 nt_chr50 := nt_chr50(NULL); l_v5 nt_chr40 := nt_chr40(NULL); l_i NUMBER := 1; BEGIN -- Using TABLE Operator to unnest collections -- Demonstrating converting local PL/SQL collection variable into a -- relational table. OPEN l_c1 FOR 'SELECT p1.dept_name, p2.* FROM dept_info p1, TABLE(CAST(proj_emp_pack.get_emp_proj(p1.projects,p1.employees) AS nt_projemp))p2 '; LOOP FETCH l_c1 INTO l_v3(l_i),l_v2(l_i),l_v5(l_i); EXIT WHEN l_c1%notfound; l_v2.EXTEND; l_v3.EXTEND; l_v5.EXTEND; l_i := l_i + 1; END LOOP; CLOSE l_c1; l_v2.TRIM; l_v3.TRIM; l_v5.TRIM; -- Displaying the Employee Name and Corresponding Project Info DBMS_OUTPUT.NEW_LINE(); DBMS_OUTPUT.NEW_LINE(); DBMS_OUTPUT.PUT_LINE(' Listing Of Employees and Current Projects : '); DBMS_OUTPUT.NEW_LINE(); DBMS_OUTPUT.PUT_LINE('--------------------------------------------' || '----------------'); DBMS_OUTPUT.PUT_LINE(' Employee Name '|| ' Project Name'); DBMS_OUTPUT.PUT_LINE('--------------------------------------------' || '----------------'); FOR l_i IN 1..l_v2.COUNT LOOP DBMS_OUTPUT.PUT_LINE(' '||l_v5(l_i)|| ' '||l_v2(l_i)); END LOOP; DBMS_OUTPUT.PUT_LINE('--------------------------------------------' || '----------------'); DBMS_OUTPUT.NEW_LINE(); END display_proj_emp; /* ------------------------------------------------------------------ */ /* Function which returns the nested table having project name and */ /* Employee Name. The input parameters to this function are */ /* a) nested table of projects */ /* b) & nested table of employees */ /* ------------------------------------------------------------------ */ FUNCTION get_emp_proj(p1 nt_project,p2 nt_employee) RETURN nt_projemp IS l_v1 VARCHAR2(10); l_v2 VARCHAR2(10); l_i NUMBER := 1; l_j NUMBER; l_k NUMBER; l_l NUMBER; l_n nt_projemp := nt_projemp(ot_proj_emp(' ',' ')); BEGIN l_j := p1.COUNT; l_k := p2.COUNT; l_n.Extend(l_j-1); FOR l_i IN 1..l_j LOOP l_v1 := p1(l_i).project_id; FOR l_l in 1..l_k LOOP l_v2 := p2(l_l).Current_Proj_Id; IF l_v1 = l_v2 THEN l_n(l_i) := ot_proj_emp(p1(l_i).project_name,p2(l_l).emp_name); EXIT; END IF; END LOOP; END LOOP; RETURN (l_n); END get_emp_proj; END proj_emp_pack; / SHOW ERRORS; SET ECHO OFF SPOOL OFF SPOOL tabdemo.lis /******************** EXECUTION BEGINS HERE *******************************/ BEGIN /* Insert Some Sample Rows into Dept_Info Table */ INSERT INTO dept_info VALUES('D1','Department 1', nt_project(ot_project('P1','Project 1',2000), ot_project('P2','Project 2',4000)), 'NewYork', nt_employee(ot_employee('E1','Employee 1','P1',1000), ot_employee('E2','Employee 2','P2',2000)) ); INSERT INTO dept_info VALUES('D2','Department 2', nt_project(ot_project('P3','Project 3',2000), ot_project('P4','Project 4',4000)), 'Sanfrancisco', nt_employee(ot_employee('E3','Employee 3','P3',1000), ot_employee('E4','Employee 4','P4',2000)) ); INSERT INTO dept_info VALUES('D3','Department 3', nt_project(ot_project('P5','Project 5',2000), ot_project('P6','Project 6',4000)), 'Washington', nt_employee(ot_employee('E5','Employee 5','P5',1000), ot_employee('E6','Employee 6','P6',2000)) ); /* Display Department Wise Employee Information */ proj_emp_pack.display_dept_emp; /* Display Department Wise Project Information */ proj_emp_pack.display_dept_projs; /* Display Employee Wise Project Information */ proj_emp_pack.display_proj_emp; END; / SPOOL OFF /***************** Clean Up ****************************************/ DROP TABLE dept_info / DROP TYPE nt_project; / DROP TYPE nt_employee; / DROP TYPE nt_projemp; / DROP TYPE ot_project; / DROP TYPE ot_employee; / DROP TYPE ot_proj_emp; / DROP TYPE nt_chr50; / DROP TYPE nt_num102; / DROP TYPE nt_chr20; / DROP TYPE nt_chr10; / DROP TYPE nt_chr40; / DROP TYPE nt_num82; /