Run a function with a table of User Defined Type (UDT) as a parameter using SQLPlus

If you want to send multiple records to an oracle function, a common practice is to create the function with one or more parameters as a table of an object type.

In the function itself, you can loop thru the array or select from it using to TABLE command.

Another option to send an array of multiple records is to use XML (xmltype) as the function parameter but this will be addressed in a separate post.

While I use this method for years, for some reason, many times I find myself struggling with the relatively simple syntax. This post will serve me (and maybe some of you) as a short, very simplistic template to copy from.

Basically, what you need to do is the create a user defined object type (UDT)

CREATE OR REPLACE TYPE order_type AS object (
  num_of_units NUMBER
, cost_of_unit NUMBER)

Then you create a table of this user defined type

CREATE OR REPLACE TYPE order_tbl AS  TABLE OF order_type

A simple function

CREATE OR REPLACE FUNCTION calc_total (i_orders order_tbl) RETURN NUMBER IS
   SELECT SUM(num_of_units * cost_of_unit)
   INTO res
   FROM TABLE (i_orders);
   RETURN res;

Testing this function with SQLPlus is a little challenging. The simple way to send a table of UDT type to a function is to cast it to the table of the user defined type.

SQL>   SELECT  calc_total(
  2                      CAST(MULTISET(
  3                        SELECT * FROM
  4                        (
  5                        SELECT 9 num_of_units, 2 cost_of_unit FROM dual UNION ALL
  6                        SELECT 6, 3  FROM dual
  7                        ) ) AS order_tbl   ))
  8    FROM dual;

The reason for the additional inline view is the weird oracle bug the cause the function to hang (and sometimes crash with ora-03113 and ora-00600 ) when using cast and multiset together with union. The inline view is fast workaround for this.
Another option to work around this problem is to use multiset union

SQL>    SELECT  calc_total( (CAST(multiset(
  2                               SELECT 9,2 FROM dual
  3                                MULTISET UNION
  4                               SELECT 6,3 FROM dual
  5                           ) AS order_tbl   ))
  6                       )
  7     FROM dual;
Share on RedditEmail this to someoneShare on Google+Share on LinkedInShare on FacebookDigg thisTweet about this on Twitter

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>