Oracle 8i | Oracle 9i | Oracle 10g | Oracle 11g | Oracle 12c | Miscellaneous | PL/SQL | SQL | Oracle RAC | Oracle Apps | Linux

Complex Recordsets

It's not always possible to build the required recordset from a single SQL query, especially when trying to produce complex reports. Sometimes several passes through the data are required to acheive the desired data. Oracle allows you to do this using temporary tables or PL/SQL tables. Although the examples in this article could easily be done using SQL alone they do illustrate the methods available.

Temporary Tables

Using this method we can create a temporary table to hold the data while we process it. Once the processing is complete we can use a REF CURSOR to pass the recordset out to an application.

First we create a temporary table to hold the data during the processing.

CREATE GLOBAL TEMPORARY TABLE my_temp_table
(
  empno         NUMBER(4),
  ename         VARCHAR2(10),
  sal           NUMBER(7,2),
  complex       NUMBER(7,2)
) ON COMMIT PRESERVE ROWS;

Next we create a package to hold a REF CURSOR type.

CREATE OR REPLACE PACKAGE types AS 
  TYPE cursor_type IS REF CURSOR;
END Types; 
/

Next a procedure is defined to use the ref cursor and the temporary table.

CREATE OR REPLACE
PROCEDURE GetComplexEmpRS (p_deptno    IN  emp.deptno%TYPE,
                           p_recordset OUT types.cursor_type) AS 
BEGIN
  -- Populate temporary table.
  INSERT INTO my_temp_table
    (empno, ename, sal)
  SELECT empno, ename, sal
  FROM   emp
  WHERE  deptno = p_deptno;
  
  -- Do complex processing that can't be done from SQL alone.
  FOR cur_row IN (SELECT * FROM my_temp_table) LOOP
    UPDATE my_temp_table
    SET    complex = cur_row.sal + 1
    WHERE  empno   = cur_row.empno;
  END LOOP;

  -- Open REF CURSOR for outout.
  OPEN p_recordset FOR
    SELECT empno,
           ename,
           sal,
           complex
    FROM   my_temp_table
    ORDER BY ename;
END GetComplexEmpRS;
/

PL/SQL Tables

This method is essentially the same only the temporary table is replaced by a PL/SQL table. First we create the relevant database types.

CREATE TYPE my_row_type AS OBJECT
(
  empno         NUMBER(4),
  ename         VARCHAR2(10),
  sal           NUMBER(7,2),
  complex       NUMBER(7,2)
);
/

Next a table type is defined using the previous object type as a rowtype.

CREATE TYPE my_tab_type IS TABLE OF my_row_type;
/

Next we create a package to hold a REF CURSOR type.

CREATE OR REPLACE PACKAGE types AS 
  TYPE cursor_type IS REF CURSOR;
END Types; 
/

Next a procedure is defined to use the ref cursor and the table type.

CREATE OR REPLACE
PROCEDURE GetComplexEmpRS (p_deptno    IN  emp.deptno%TYPE,
                           p_recordset OUT types.cursor_type) AS 
  v_tab  my_tab_type := my_tab_type();
BEGIN
  
  -- Populate PL/SQL table.
  FOR cur_row IN (SELECT * FROM emp WHERE deptno = p_deptno) LOOP
    v_tab.extend;
    v_tab(v_tab.Last) := my_row_type(cur_row.empno, cur_row.ename, cur_row.sal, NULL);
  END LOOP;

  -- Do complex processing that can't be done from SQL alone.
  FOR cur_row IN 1 .. v_tab.count LOOP
    v_tab(cur_row).complex := v_tab(cur_row).sal + 1;
  END LOOP;
  
  -- Open REF CURSOR for outout.
  OPEN p_recordset FOR
    SELECT empno,
           ename,
           sal,
           complex
    FROM   TABLE(CAST(v_tab As my_tab_type))
    ORDER BY ename; 
END GetComplexEmpRS;
/

The TABLE and CAST functions allow the PL/SQL table to be referenced from SQL.

Test It

Finally the recordset can be referenced using PL/SQL, Java, ADO etc. The following example uses ADO.

Dim conn, cmd, rs

Set conn = Server.CreateObject("adodb.connection")
conn.Open "DSN=TSH1;UID=scott;PWD=tiger"

Set cmd = Server.CreateObject ("ADODB.Command")
Set cmd.ActiveConnection = conn
cmd.CommandText = "GetComplexEmpRS"
cmd.CommandType = 4 'adCmdStoredProc

Dim param1
Set param1 = cmd.CreateParameter ("deptno", adInteger, adParamInput)
cmd.Parameters.Append param1
param1.Value = 30

Set rs = cmd.Execute

Do Until rs.BOF Or rs.EOF
  -- Do something
  rs.MoveNext
Loop

rs.Close
conn.Close
Set rs     = nothing
Set param1 = nothing
Set cmd    = nothing
Set conn   = nothing

For more information see:

Hope this helps. Regards Tim...

Back to the Top.