Overview
        
          You may need the Result Set from a Query in your .NET or Java Code
          by calling a Stored Procedure. Here are some samples for SQL Server and Oracle
          10g. 
         
        Returning simple Result Sets using SQL Server
        
          With SQL Server 2000/2005 it is very easy to return a Result Set
          from a Query to the calling environment. Here is an example using SQL Query
          Analyzer. 
          USE Northwind 
          GO 
           
          CREATE PROCEDURE MyOrders 
          AS 
             SELECT * FROM
          Orders 
             WHERE RequiredDate < GETDATE() AND
          ShippedDate IS NULL 
          GO 
           
          EXEC MyOrders 
          GO 
         
        Returning complex Result Sets using SQL Server
        
          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 get the desired
          data. 
          CREATE FUNCTION
          CustAdresse(@PersID
          bigint, @KontaktArtID bigint)  RETURNS @addresstable TABLE     (PersonID  bigint, 
              Adresse   varchar(50)
          COLLATE database_default, 
              PLZ       varchar(10) COLLATE
          database_default, 
              Ort       varchar(50) COLLATE
          database_default, 
              Land      varchar(50) COLLATE
          database_default)  AS 
          BEGIN   
          DECLARE @KontaktID bigint 
              IF (@KontaktArtID = 1)  
            BEGIN      SET @KontaktID
          = (SELECT k.KontaktID 
                                 
          FROM Kontakt k 
                                
          WHERE k.KontaktArtID = 1                          
          AND k.PersonID = @PersID) 
            END 
              IF (@KontaktID IS NULL)  
            BEGIN      SET @KontaktID
          = (SELECT k.KontaktID 
                                 
          FROM Kontakt k 
                                
          WHERE k.KontaktArtID = 2 
                                  
          AND k.PersonID = @PersID 
            END 
                INSERT
          INTO @addresstable 
                (k.PersonID, Adresse, PlZ, Ort, Land) 
                SELECT k.Personid,
          k.Adresse, o.PLZ, l.Land 
                  FROM Kontakt k, Ort
          o, Land l 
                  WHERE k.OrtID = o.OrtID 
                   AND o.LandID
          = l.LandID 
                   AND
          k.KontaktID = @KontaktID 
            RETURN  END 
          In SQL Server, you can declare a temporary Table (@addresstable) within the T_SQL
          Code. In the code you fill this Table using your own Business Logic and then return this
          Table back to the calling environment. 
         
        Returning simple Result Sets using Oracle 10g
        
          Using a REF CURSOR it is quite easy to give
          access to the content of a database table from either PL/SQL or Java, or most other
          programming languages, for that matter. 
          REF CURSORS have been available which allow recordsets
          to be returned from stored procedures, functions and packages. The example below uses a
          ref cursor to return a subset of the records in the EMP table. 
         
        Create the simple EMP and DEPT Tables. 
        
          DROP TABLE EMP; 
          DROP TABLE DEPT; 
           
          CREATE TABLE EMP 
             (EMPNO NUMBER(4), 
              ENAME VARCHAR2(10), 
              JOB VARCHAR2(9), 
              MGR NUMBER(4), 
              HIREDATE DATE, 
              SAL NUMBER(7,2), 
              COMM NUMBER(7,2), 
              DEPTNO NUMBER(2)); 
           
          INSERT INTO EMP VALUES (7369,'SMITH','CLERK',7902,'17-DEC-80',800,NULL,20); 
          INSERT INTO EMP VALUES (7499,'ALLEN','SALESMAN',7698,'20-FEB-81',1600,300,30); 
          INSERT INTO EMP VALUES (7521,'WARD','SALESMAN',7698,'22-FEB-81',1250,500,30); 
          INSERT INTO EMP VALUES (7566,'JONES','MANAGER',7839,'2-APR-81',2975,NULL,20); 
          INSERT INTO EMP VALUES (7654,'MARTIN','SALESMAN',7698,'28-SEP-81',1250,1400,30); 
          INSERT INTO EMP VALUES (7698,'BLAKE','MANAGER',7839,'1-MAY-81',2850,NULL,30); 
          INSERT INTO EMP VALUES (7782,'CLARK','MANAGER',7839,'9-JUN-81',2450,NULL,10); 
          INSERT INTO EMP VALUES (7788,'SCOTT','ANALYST',7566,'09-DEC-82',3000,NULL,20); 
          INSERT INTO EMP VALUES (7839,'KING','PRESIDENT',NULL,'17-NOV-81',5000,NULL,10); 
          INSERT INTO EMP VALUES (7844,'TURNER','SALESMAN',7698,'8-SEP-81',1500,0,30); 
          INSERT INTO EMP VALUES (7876,'ADAMS','CLERK',7788,'12-JAN-83',1100,NULL,20); 
          INSERT INTO EMP VALUES (7900,'JAMES','CLERK',7698,'3-DEC-81',950,NULL,30); 
          INSERT INTO EMP VALUES (7902,'FORD','ANALYST',7566,'3-DEC-81',3000,NULL,20); 
          INSERT INTO EMP VALUES (7934,'MILLER','CLERK',7782,'23-JAN-82',1300,NULL,10); 
          COMMIT; 
           
          CREATE TABLE DEPT 
                 (DEPTNO NUMBER(2), 
                  DNAME VARCHAR2(14), 
                  LOC VARCHAR2(13) ); 
           
          INSERT INTO DEPT VALUES (10,'ACCOUNTING','NEW YORK'); 
          INSERT INTO DEPT VALUES (20,'RESEARCH','DALLAS'); 
          INSERT INTO DEPT VALUES (30,'SALES','CHICAGO'); 
          INSERT INTO DEPT VALUES (40,'OPERATIONS','BOSTON'); 
          COMMIT; 
           
          ALTER TABLE EMP ADD CONSTRAINT PK_EMP PRIMARY KEY (EMPNO); 
          ALTER TABLE DEPT ADD CONSTRAINT PK_DEPT PRIMARY KEY (DEPTNO); 
         
        Create a Package with a REF CURSOR 
        
          CREATE OR REPLACE PACKAGE GetEmpPckg IS 
            -- Strongly Typed REF CURSOR 
          -- A REF CURSOR that specifies a specific return type 
          TYPE emp_ref_cursor IS REF CURSOR RETURN
          emp%ROWTYPE;  --  --
          Weakly Typed 
          -- A REF CURSOR that does not specify the return type such as SYS_REFCURSOR  --
          TYPE emp_ref_cursor IS REF CURSOR; 
          PROCEDURE GetEmp 
            (p_dep  IN  emp.deptno%TYPE, 
             p_ref  OUT emp_ref_cursor); 
          END GetEmpPckg; 
          / 
           
          CREATE OR REPLACE PACKAGE BODY GetEmpPckg IS 
          PROCEDURE GetEmp 
            (p_dep  IN  emp.deptno%TYPE, 
             p_ref  OUT emp_ref_cursor)
          IS 
             BEGIN 
             OPEN p_ref FOR 
               SELECT empno, ename, job, mgr, hiredate, sal, comm, deptno 
                 FROM emp 
                WHERE deptno = p_dep 
                ORDER BY ename; 
             END; 
          END GetEmpPckg; 
          / 
          In Oracle9i the SYS_REFCURSOR type has been added making the TYPE emp_ref_cursor step unnecessary. If you are using Oracle9i or
          later simply ignore this and replace any references to emp_ref_cursor with SYS_REFCURSOR. 
         
        Test the REF CURSOR Procedure from within PL/SQL 
        
          The resulting cursor can be referenced from PL/SQL
          as follows: 
          
SET SERVEROUTPUT ON SIZE 1000000
DECLARE
  v_cursor     GetEmpPckg.emp_ref_cursor;
  v_empno      emp.empno%TYPE;
  v_ename      emp.ename%TYPE;
  v_job        emp.job%TYPE;
  v_mgr        emp.mgr%TYPE;
  v_hiredate   emp.hiredate%TYPE;
  v_sal        emp.sal%TYPE;
  v_comm       emp.comm%TYPE;
  v_deptno     emp.deptno%TYPE;
BEGIN
  GetEmpPckg.GetEmp (p_dep => 30,
                     p_ref => v_cursor);
  LOOP
    FETCH v_cursor
    INTO  v_empno, v_ename, v_job, v_mgr, v_hiredate, v_sal, v_comm, v_deptno;
    EXIT WHEN v_cursor%NOTFOUND;
    DBMS_OUTPUT.PUT_LINE(v_ename || ' | ' || v_empno || ' | ' || v_deptno);
  END LOOP;
  CLOSE v_cursor;
END;
/
          ALLEN  | 7499 | 30 
          BLAKE  | 7698 | 30 
          JAMES  | 7900 | 30 
          MARTIN | 7654 | 30 
          TURNER | 7844 | 30 
          WARD   | 7521 | 30 
         
        Test the REF CURSOR Procedure from within C# 
        
          using System; 
          using System.Data; 
          using Oracle.DataAccess.Client; 
           
          class Sample 
          { 
              static void Main() 
              { 
                  // Connect to
          Oracle 
                  string constr = "User
          Id=scott;Password=tiger;Data Source=AKI1.WORLD"; 
                  OracleConnection con = new
          OracleConnection(constr); 
                  con.Open(); 
           
                  // Display Version
          Number 
                  Console.WriteLine("Connected to Oracle " +
          con.ServerVersion); 
           
                  // Read REF CURSOR into
          DataSet 
                  DataSet ds = new DataSet(); 
                  OracleCommand cmd = con.CreateCommand(); 
           
                  cmd.CommandText = "GetEmpPckg.GetEmp"; 
                  cmd.CommandType =
          CommandType.StoredProcedure; 
                  cmd.Parameters.Add("p_dep",
          OracleDbType.Int16).Value = 20; 
                  cmd.Parameters.Add("p_ref",
          OracleDbType.RefCursor).Direction 
                       =
          ParameterDirection.Output; 
           
                  OracleDataAdapter da = new
          OracleDataAdapter(cmd); 
                  da.TableMappings.Add("Emp", "Emp"); 
                  da.Fill(ds); 
           
                  // Close and Dispose
          OracleConnection 
                  con.Close(); 
                  con.Dispose(); 
           
                  // Show
          Message 
                  Console.WriteLine("DataSet filled"); 
              } 
          } 
         
        Returning complex Result Sets using Oracle 10g
        
          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. 
         
        
        
          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; 
         
        
        
          CREATE OR REPLACE PACKAGE GetComplexPkg IS 
          PROCEDURE GetEmp 
            (p_dep IN  emp.deptno%TYPE, 
             p_ref OUT SYS_REFCURSOR); 
          END GetComplexPkg ; 
          / 
          CREATE OR REPLACE PACKAGE BODY GetComplexPkg
          IS 
          PROCEDURE GetEmp    (p_dep IN 
          emp.deptno%TYPE, 
             p_ref OUT SYS_REFCURSOR) AS 
          BEGIN 
            -- Populate temporary table. 
            INSERT INTO my_temp_table 
              (empno, ename, sal) 
            SELECT empno, ename, sal 
            FROM   emp 
            WHERE  deptno = p_dep; 
            
            -- 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 Output. 
            OPEN p_ref FOR 
              SELECT empno, 
                     ename, 
                     sal, 
                     complex 
               FROM  my_temp_table 
              ORDER BY ename;  END; 
          END GetComplexPkg; 
          / 
         
        PL/SQL Tables 
        
          This method is essentially the same only the temporary table is
          replaced by a PL/SQL table. 
         
        
        
          CREATE TYPE My_Row_Type AS OBJECT
          (    empno         NUMBER(4), 
            ename        
          VARCHAR2(10),    sal          
          NUMBER(7,2),    complex       NUMBER(7,2)); 
          / 
         
        
        
          CREATE TYPE My_Tab_Type IS TABLE OF
          My_Row_Type; 
          / 
         
        
        
          CREATE OR REPLACE PACKAGE GetComplexTabPkg IS 
          PROCEDURE GetEmp 
            (p_dep IN  emp.deptno%TYPE, 
             p_ref OUT SYS_REFCURSOR); 
          END GetComplexTabPkg; 
          / 
           
          CREATE OR REPLACE PACKAGE BODY GetComplexTabPkg IS 
          PROCEDURE GetEmp    (p_dep IN 
          emp.deptno%TYPE, 
             p_ref OUT SYS_REFCURSOR) AS 
             v_tab  My_Tab_Type := My_Tab_Type(); 
          BEGIN 
            
            -- Populate PL/SQL table. 
            FOR cur_row IN (SELECT * FROM emp WHERE deptno = p_dep) 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 Output. 
            OPEN p_ref FOR 
              SELECT empno, 
                     ename, 
                     sal, 
                     complex 
              FROM   Table(Cast(v_tab As My_Tab_Type)) 
              ORDER BY ename;  END; 
          END GetComplexTabPkg; 
          / 
         
        Test the REF CURSOR Procedure from within C# 
        
          using System; 
          using System.Data; 
          using Oracle.DataAccess.Client; 
           
          class Sample 
          { 
              static void Main() 
              { 
                  // Connect to
          Oracle 
                  string constr = "User
          Id=scott;Password=tiger;Data Source=AKI1.WORLD"; 
                  OracleConnection con = new
          OracleConnection(constr); 
                  con.Open(); 
           
                  // Display Version
          Number 
                  Console.WriteLine("Connected to Oracle " +
          con.ServerVersion); 
           
                  // Read REF CURSOR into
          DataSet 
                  DataSet ds = new DataSet(); 
                  OracleCommand cmd = con.CreateCommand(); 
           
                  cmd.CommandText = "GetComplexTabPkg.GetEmp"; 
                  cmd.CommandType =
          CommandType.StoredProcedure; 
                  cmd.Parameters.Add("p_dep",
          OracleDbType.Int16).Value = 20; 
                  cmd.Parameters.Add("p_ref",
          OracleDbType.RefCursor).Direction 
                       =
          ParameterDirection.Output; 
           
                  OracleDataAdapter da = new
          OracleDataAdapter(cmd); 
                  da.TableMappings.Add("Emp", "Emp"); 
                  da.Fill(ds); 
           
                  // Close and Dispose
          OracleConnection 
                  con.Close(); 
                  con.Dispose(); 
           
                  // Show
          Message 
                  Console.WriteLine("DataSet filled"); 
              } 
          } 
         
        Referenced Documents 
        
          http://www.psoug.org/reference/ref_cursors.html 
          http://www.oracle-base.com/index.php 
          
          http://msdn2.microsoft.com/en-us/library/system.data.oracleclient.oracledataadapter.aspx 
          WHERE
          Klausel Generierung mit .NET, Urs Meier, Trivadis AG 
         
       |