Avatar of wanderingbob
wanderingbobFlag for United States of America

asked on 

Oracle 10g / PL-SQL: How to SELECT FROM a function that returns a collection or ref cursor?

My company is implementing an ERP system that uses an Oracle 10g database as its repository.  Because this ERP system is being implemented across multiple companies, and because of upgrade and migration issues, none of the objects in the ERP system database can be modified.  I'm using Toad as PL/SQL editor.

My responsibility is to create reports to provide information missing from the reports included with the ERP system. No specific formatting is needed for the reports I'm creating, so all that usually needs to be done is to create a SQL statement which is stored in a column in an ad hoc report table.  When the SQL
statement is executed, the ERP system automatically creates an interface for the user to assign values to any bind variables, then displays the results in a data grid.  The column that stores the SQL statement is limited to 4000 bytes, so if the report is a very complex one, the SQL statement exceeds the length
of the column.  Modifications to the existing schema objects, such as changing the column in the ad hoc table to a clob, are not possible for reasons cited above.

One solution to this problem is to create a view that encapsulates each long SQL statement, then select from the view.  Unfortunately, this is considered unacceptable because it would result in the creation of dozens or hundreds of views, which would have to be maintained over time as database changes,
upgrades, and migration take place.

The approach I am attempting is to create one large package which includes multiple functions, one for each long SQL statement.  A brief SQL statement in the ad hoc table would call the corresponding function in the package, which would return multiple rows.  I know this can be done by having either a collection or ref cursor as the function's return type.  I need to be able to SELECT FROM the function to access the multiple rows in the collection or ref cursor.

I have been able to successfully SELECT FROM a function returning a ref cursor, which produces a ref cursor.  In Toad the results grid displays "(REF CURSOR)", and that column in the results grid can be opened to display the multiple rows within the ref cursor.  However, although Toad "understands" the ref cursor, the ERP system does not and cannot accept the ref cursor as input.

I have attempted, but am unable to successfully SELECT FROM a function returning a collection.

My example (function returning collection):

---

CREATE OR REPLACE PACKAGE TEMP_REPORT_PKG IS

TYPE Row_Set IS REF CURSOR;

TYPE Compare_BOM_Row IS RECORD (
eng_level            VARCHAR2(10),
eng_part_no          VARCHAR2(25),
eng_part_description VARCHAR2(50),
part_state           VARCHAR2(1),
eng_qty_assy         NUMBER,
eng_uom              VARCHAR2(10),
inv_level            VARCHAR2(10),
inv_part_no          VARCHAR2(25),
inv_part_description VARCHAR2(50),
part_status          VARCHAR2(25),
inv_qty_assy         NUMBER,
inv_uom              VARCHAR2(10)
);

TYPE Compare_BOM IS TABLE OF Compare_BOM_Row;

FUNCTION Compare_Bills_Of_Material (
std_name_ IN VARCHAR2,
part_no_ IN VARCHAR2,
rev_ IN VARCHAR2,
eff_date_ IN DATE,
contract_ IN VARCHAR2,
max_level_ IN NUMBER) RETURN Compare_BOM;

END TEMP_REPORT_PKG;

---

CREATE OR REPLACE PACKAGE BODY TEMP_REPORT_PKG IS

FUNCTION Compare_Bills_Of_Material (
  std_name_ IN VARCHAR2,
  part_no_ IN VARCHAR2,
  rev_ IN VARCHAR2,
  eff_date_ IN DATE,
  contract_ IN VARCHAR2,
  max_level_ IN NUMBER ) RETURN Compare_BOM
IS
  temp_ Row_Set;
  compare_bom_ Compare_BOM;
 
  BEGIN
  OPEN temp_ FOR

  ...long, complex SELECT FROM statement ...

  FETCH temp_ BULK COLLECT INTO compare_bom_;
  RETURN compare_bom_;
END Compare_Bills_Of_Material;

END TEMP_REPORT_PKG;

---

If I attempt to consume this function as follows:

SELECT TEMP_REPORT_PKG.Compare_Bills_Of_Material('Company Specific', '5477B-744', 'A', '30-JUN-08','CO001', 3) FROM DUAL

or

SELECT * FROM TABLE (SELECT TEMP_REPORT_PKG.Compare_Bills_Of_Material('Company Specific', '5477B-744', 'A', '30-JUN-08','CO001', 3) FROM DUAL)

I receive ORA-00902: Invalid datatype.  How can I SELECT FROM a function that returns a collection or ref cursor?

Thanks in advance,
Bob
Oracle Database

Avatar of undefined
Last Comment
wanderingbob
Avatar of knowledge_riot
knowledge_riot
Flag of United Kingdom of Great Britain and Northern Ireland image

Have you tried the following?

SELECT * FROM TABLE(TEMP_REPORT_PKG.Compare_Bills_Of_Material('Company Specific', '5477B-744', 'A', '30-JUN-08','CO001', 3) )
Avatar of gajmp
gajmp

SELECT TEMP_REPORT_PKG.Compare_Bills_Of_Material('Company Specific', '5477B-744', 'A', to_date('30-JUN-08','dd-mon-yy'),'CO001', 3) FROM DUAL
Avatar of wanderingbob
wanderingbob
Flag of United States of America image

ASKER

Thanks for the suggestions.  Unfortunately, both

SELECT * FROM TABLE(TEMP_REPORT_PKG.Compare_Bills_Of_Material('Company Specific', '5477B-744', 'A', '30-JUN-08','CO001', 3) )

and

SELECT TEMP_REPORT_PKG.Compare_Bills_Of_Material('Company Specific', '5477B-744', 'A', to_date('30-JUN-08','dd-mon-yy'),'CO001', 3) FROM DUAL

still return the same error.  As an alternative, is there a way to "open" the ref cursor in a SELECT FROM statement such that the result is the collection of rows in the ref cursor (indistinguishable from the collection of rows returned by the SELECT FROM statement embedded in the function being called), rather than the ref cursor iteslf?

Thank you,
Bob

ASKER CERTIFIED SOLUTION
Avatar of wanderingbob
wanderingbob
Flag of United States of America image

Blurred text
THIS SOLUTION IS ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
Avatar of wanderingbob
wanderingbob
Flag of United States of America image

ASKER

Update: The ORA-06504 (Return types ... do not match) at the FETCH ... BUILK COLLECT INTO ... has been solved by re-engineering the FETCH part of the function.  Apparently, since the ref cursor points to a resultset with 12 columns, it must be FETCHed into 12 columns, BUILK COLLECT INTO not withstanding.  The re-engineered package body is below:

CREATE OR REPLACE PACKAGE BODY TEMP_REPORT_PKG IS

FUNCTION Compare_Bills_Of_Material (
  std_name_ IN VARCHAR2,
  part_no_ IN VARCHAR2,
  rev_ IN VARCHAR2,
  eff_date_ IN DATE,
  contract_ IN VARCHAR2,
  max_level_ IN NUMBER ) RETURN Compare_BOM
IS

  temp_cursor_ SYS_REFCURSOR;
  index_ Number := 1;
  compare_bom_ Compare_BOM := Compare_Bom();
 
  BEGIN

  OPEN temp_cursor_ FOR
 
... long, complex SELECT FROM statement ...

LOOP

  -- PL-SQL TABLE TYPES (COLLECTIONS) ARE 1-BASED
  compare_bom_.EXTEND;
  compare_bom_(index_) := Compare_BOM_Row('','','','',0,'','','','','',0,'');
  FETCH temp_cursor_ INTO compare_bom_(index_).eng_level,
  compare_bom_(index_).eng_part_no,
  compare_bom_(index_).eng_part_description,
  compare_bom_(index_).part_state,
  compare_bom_(index_).eng_qty_assy,
  compare_bom_(index_).eng_uom,
  compare_bom_(index_).inv_level,
  compare_bom_(index_).inv_part_no,
  compare_bom_(index_).inv_part_description,
  compare_bom_(index_).part_status,
  compare_bom_(index_).inv_qty_assy,
  compare_bom_(index_).inv_uom;
  index_ := index_ + 1;
  EXIT WHEN temp_cursor_%NOTFOUND;
 
END LOOP;
 
    RETURN compare_bom_;
 
END Compare_Bills_Of_Material;

END TEMP_QUICK_REPORT_API;

Thanks to you both for your suggestions.

Bob
Oracle Database
Oracle Database

Oracle is an object-relational database management system. It supports a large number of languages and application development frameworks. Its primary languages are SQL, PL/SQL and Java, but it also includes support for C and C++. Oracle also has its own enterprise modules and application server software.

81K
Questions
--
Followers
--
Top Experts
Get a personalized solution from industry experts
Ask the experts
Read over 600 more reviews

TRUSTED BY

IBM logoIntel logoMicrosoft logoUbisoft logoSAP logo
Qualcomm logoCitrix Systems logoWorkday logoErnst & Young logo
High performer badgeUsers love us badge
LinkedIn logoFacebook logoX logoInstagram logoTikTok logoYouTube logo