Home » SQL & PL/SQL » SQL & PL/SQL » Viewing Object values in select (11.2.0.1.0)
Viewing Object values in select [message #636997] Thu, 07 May 2015 06:21 Go to next message
OraFerro
Messages: 433
Registered: July 2011
Senior Member
Hi All,

I have a user created type that has two values. I have a function that returns back an object of this type. When I use a select statement to select some values in addition to this function, as per the below example:


CREATE OR REPLACE TYPE AFESD2."AMOUNT2"  AS OBJECT
(
  "AMT1" NUMBER(15,3),
  "AMT2" NUMBER(15,3)
);

CREATE OR REPLACE FUNCTION F_try(Req_No in number, exch_rate_date in char default 'TODAY')   
Return Amount2 As  
Trans_Amts Amount2;
   
Amt1 Number;    
Amt2 Number; 
STAT NUMBER;   

 begin

SELECT 5,6
  INTO AMT1,
       AMT2
  FROM DUAL;
	Trans_Amts := AMOUNT2(AMT1,AMT2);
	RETURN (Trans_Amts);

END;
/

select 1, f_try(3) from dual;


I need to know if I can write a select (or any other way) in order to get 1, 5, 6 as three separate columns.

Many Thanks,
Ferro
Re: Viewing Object values in select [message #636998 is a reply to message #636997] Thu, 07 May 2015 06:26 Go to previous messageGo to next message
John Watson
Messages: 9003
Registered: January 2010
Location: Global Village
Senior Member
orclz> select 1, f_try(3).amt1,f_try(3).amt2 from dual;

         1 F_TRY(3).AMT1 F_TRY(3).AMT2
---------- ------------- -------------
         1             5             6

orclz>

Re: Viewing Object values in select [message #636999 is a reply to message #636998] Thu, 07 May 2015 06:32 Go to previous messageGo to next message
OraFerro
Messages: 433
Registered: July 2011
Senior Member
Thank John,

I guess this way the function has to run twice (the real function is more complex) is there a way to split the object values in the select without running the function twice?

Ferro
Re: Viewing Object values in select [message #637000 is a reply to message #636999] Thu, 07 May 2015 06:41 Go to previous messageGo to next message
Michel Cadot
Messages: 68776
Registered: March 2007
Location: Saint-Maur, France, https...
Senior Member
Account Moderator

Quote:
I guess this way the function has to run twice


Do not guess, test it.
1/ Define your function as deterministic, it is
2/Add a dbms_output.put_line or an insert into a log table inside the function and verify what is done.

Re: Viewing Object values in select [message #637001 is a reply to message #637000] Thu, 07 May 2015 07:06 Go to previous messageGo to next message
OraFerro
Messages: 433
Registered: July 2011
Senior Member
Thanks Michel for the advice, I am sure now, it runs once every time the function is selected.

CREATE OR REPLACE FUNCTION F_try(Req_No in number, exch_rate_date in char default 'TODAY')   
Return Amount2 As  
Trans_Amts Amount2;
   
Amt1 Number;    
Amt2 Number; 
STAT NUMBER;   

 begin

SELECT 5,6
  INTO AMT1,
       AMT2
  FROM DUAL;

DBMS_OUTPUT.PUT_LINE('One run');

	Trans_Amts := AMOUNT2(AMT1,AMT2);
	RETURN (Trans_Amts);

END;

select 1, f_try(3).AMT1, F_TRY(3).AMT2, f_try(3).AMT1 from dual;

One run
One run
One run


Quote:

is there a way to split the object values in the select without running the function twice?


Ferro
Re: Viewing Object values in select [message #637003 is a reply to message #637001] Thu, 07 May 2015 07:48 Go to previous messageGo to next message
bugfox
Messages: 18
Registered: October 2010
Junior Member
what about:

select t.id,
       t.val.AMT1,
       t.val.AMT2
from (select 1 id, 
             f_try(3) val 
      from dual) t;
Re: Viewing Object values in select [message #637005 is a reply to message #637003] Thu, 07 May 2015 07:51 Go to previous messageGo to next message
John Watson
Messages: 9003
Registered: January 2010
Location: Global Village
Senior Member
I still get multiple executions, even though I added the DETERMINISTIC keyword:
orclz> select t.id,
  2         t.val.AMT1,
  3         t.val.AMT2
  4  from (select 1 id,
  5               f_try(3) val
  6        from dual) t;

        ID   VAL.AMT1   VAL.AMT2
---------- ---------- ----------
         1          5          6

One run
One run
orclz>


orclz> ed
Wrote file afiedt.buf

  1  CREATE OR REPLACE FUNCTION F_try(Req_No in number, exch_rate_date in char default 'TODAY')
  2  Return Amount2
  3  deterministic
  4  As
  5  Trans_Amts Amount2;
  6  Amt1 Number;
  7  Amt2 Number;
  8  STAT NUMBER;
  9   begin
 10  SELECT 5,6
 11    INTO AMT1,
 12         AMT2
 13    FROM DUAL;
 14  DBMS_OUTPUT.PUT_LINE('One run');
 15     Trans_Amts := AMOUNT2(AMT1,AMT2);
 16     RETURN (Trans_Amts);
 17* END;
orclz> /

Function created.




Re: Viewing Object values in select [message #637006 is a reply to message #637005] Thu, 07 May 2015 08:00 Go to previous messageGo to next message
bugfox
Messages: 18
Registered: October 2010
Junior Member
correction:

select t.id,
       t.val.AMT1,
       t.val.AMT2,
       t.val.AMT1 AMT1_2,
       t.val.AMT2 AMT2_2
from (select 1 id, 
             (select f_try(3) from dual) val 
      from dual) t;
Re: Viewing Object values in select [message #637007 is a reply to message #637006] Thu, 07 May 2015 08:01 Go to previous messageGo to next message
John Watson
Messages: 9003
Registered: January 2010
Location: Global Village
Senior Member
sussed:
orclz>
orclz> select t.id,
  2         t.val.AMT1,
  3         t.val.AMT2,
  4         t.val.AMT1 AMT1_2,
  5         t.val.AMT2 AMT2_2
  6  from (select 1 id,
  7               (select f_try(3) from dual) val
  8        from dual) t;

        ID   VAL.AMT1   VAL.AMT2     AMT1_2     AMT2_2
---------- ---------- ---------- ---------- ----------
         1          5          6          5          6

One run
orclz>
Re: Viewing Object values in select [message #637008 is a reply to message #637007] Thu, 07 May 2015 08:26 Go to previous messageGo to next message
Michel Cadot
Messages: 68776
Registered: March 2007
Location: Saint-Maur, France, https...
Senior Member
Account Moderator

You rediscover what Tom explained us long time ago. Smile

Re: Viewing Object values in select [message #637010 is a reply to message #637008] Thu, 07 May 2015 08:45 Go to previous messageGo to next message
Michel Cadot
Messages: 68776
Registered: March 2007
Location: Saint-Maur, France, https...
Senior Member
Account Moderator

Here are 3 answers from Tom on AskTom where he explained us and give us a tip to decrease the number of function calls using a FBI:
https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:3575529924010#10376065660316
https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:1547006324238#10897337104699
https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:1547006324238#15384406775542

[Updated on: Thu, 07 May 2015 08:48]

Report message to a moderator

Re: Viewing Object values in select [message #637014 is a reply to message #637010] Thu, 07 May 2015 11:20 Go to previous messageGo to next message
Solomon Yakobson
Messages: 3312
Registered: January 2010
Location: Connecticut, USA
Senior Member
I wish it would be that easy. Deterministic will not help here. For some unknown reason function returning an object is called each time you reference it directly or indirectly. The only workaround I found is use nested table:

SQL> CREATE OR REPLACE TYPE AMOUNT2  AS OBJECT
  2  (
  3    "AMT1" NUMBER(15,3),
  4    "AMT2" NUMBER(15,3)
  5  )
  6  /

Type created.

SQL> CREATE OR REPLACE
  2    TYPE AMOUNT2_TBL
  3      AS TABLE OF AMOUNT2
  4  /

Type created.

SQL> CREATE OR REPLACE FUNCTION F_try(Req_No in number, exch_rate_date in char default 'TODAY')   
  2  Return Amount2 As  
  3  Trans_Amts Amount2;
  4     
  5  Amt1 Number;    
  6  Amt2 Number; 
  7  STAT NUMBER;   
  8  
  9   begin
 10  
 11  SELECT 5,6
 12    INTO AMT1,
 13         AMT2
 14    FROM DUAL;
 15   Trans_Amts := AMOUNT2(AMT1,AMT2);
 16  DBMS_OUTPUT.PUT_LINE('Fire!');
 17   RETURN (Trans_Amts);
 18  
 19  END;
 20  /

Function created.

SQL> SELECT  1,
  2          p.*
  3    FROM  TABLE(AMOUNT2_TBL(f_try(3))) p
  4  /

         1       AMT1       AMT2
---------- ---------- ----------
         1          5          6

Fire!
SQL> 


SY.
Re: Viewing Object values in select [message #637015 is a reply to message #637014] Thu, 07 May 2015 11:27 Go to previous messageGo to next message
John Watson
Messages: 9003
Registered: January 2010
Location: Global Village
Senior Member
I think you have hit on the problem, SY - the function returns an object, which has all sorts of restrictions. For example, I tried to sneak up on the problem by adding the RESULT CACHE clause, but that doesn't compile:
Errors for FUNCTION F_TRY:

LINE/COL ERROR
-------- -----------------------------------------------------------------
0/0      PL/SQL: Compilation unit analysis terminated
2/9      PLS-00999: implementation restriction (may be temporary)
         RESULT_CACHE is disallowed on subprograms with RETURN parameter
         of (or containing) object type

orclz>
This is in 12.1.0.2.
Re: Viewing Object values in select [message #637114 is a reply to message #637015] Mon, 11 May 2015 01:10 Go to previous message
OraFerro
Messages: 433
Registered: July 2011
Senior Member
Thanks SY and all,

This solution works perfect and even when I use it in a stored procedure (which is the main purpose) it works just fine. However I have a more general question.

For using the function I need to create a user type (table) in order to use in the the FROM clause and freely choose function object variables in the select. Another approach is to replace the function and its mapping table with a view that produces the table in the from clause.

The only disadvantage that I can see with the view approach is that the view will run on the full table without any filter clause until it is filtered with a where clause when called in the stored procedure.

I appreciate if you can correct me or add any points that can help me decide between the two approaches.


--test table
create table t_try1 (v1 number, v2 number, v3 number);

INSERT ALL
  INTO t_try1 VALUES (1, 15, 67)
  INTO t_try1 VALUES (2, 16, 3)
  INTO t_try1 VALUES (11, 85, 49)
  INTO t_try1 VALUES (22, 56, 13)
  INTO t_try1 VALUES (13, 25, 7)
  INTO t_try1 VALUES (42, 156, 31)
  INTO t_try1 VALUES (51, 35, 47)
  INTO t_try1 VALUES (2, 656, 43)
  INTO t_try1 VALUES (10, 95, 647)
  INTO t_try1 VALUES (20, 596, 443)
SELECT * FROM DUAL;


--function approach
 CREATE OR REPLACE FUNCTION F_try(Req_No in number, exch_rate_date in char default 'TODAY')   
    Return Amount2 As  
    Trans_Amts Amount2;
       
    Amt1 Number;    
    Amt2 Number; 
    STAT NUMBER;   
   
    begin
   
   SELECT V2 * 6,V1 *8
     INTO AMT1,
          AMT2
     FROM T_TRY1 
    where V3 = Req_No ; --the where clause
    Trans_Amts := AMOUNT2(AMT1,AMT2);
   DBMS_OUTPUT.PUT_LINE('Fire!');
    RETURN (Trans_Amts);
   
   END;


 SELECT  1,
           p.*
      FROM  TABLE(AMOUNT2_TBL(f_try(49))) p;



create or replace  procedure p_try
  ( param1 in number, CUR_REF     OUT SYS_REFCURSOR) as
  begin
  OPEN CUR_REF FOR SELECT 1, 
                          p.amt1 zz, p.*
  FROM TABLE (AMOUNT2_TBL(f_try(param1))) p;
 END;

--view approach
create or replace view v_try
  as
  (
      SELECT V2 * 6 vv2,V1 *8 vv1, V3
     FROM T_TRY1 
  );


create or replace  procedure p_try2
  ( param1 in number, CUR_REF     OUT SYS_REFCURSOR) as
  begin
  OPEN CUR_REF FOR SELECT 1, 
                          p.vv1 zz, p.vv1, p.vv2
  FROM v_try p
  where v3 = param1; --where clause 
 END;


Thanks
Ferro

[Updated on: Mon, 11 May 2015 01:37]

Report message to a moderator

Previous Topic: PRAGMA EXCEPTION_INIT not working as desired
Next Topic: PL/SQL Tables
Goto Forum:
  


Current Time: Wed Jul 29 23:50:49 CDT 2026