Skip to Main Content
  • Questions
  • Double select from same parametrized view

Breadcrumb

Question and Answer

Chris Saxon

Thanks for the question, Kolhun.

Asked: October 12, 2016 - 1:25 pm UTC

Last updated: October 13, 2016 - 2:44 pm UTC

Version: Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production

Viewed 1000+ times

You Asked

Dear all,
I'm trying to use parameterized view, and i need select from
some view twice with different values of same parameter vie UNION ALL.

Could you say, having considered the above example, is it possible
that the both queries will use only one of two values (g_date1 or g_date2)
before reading data (due to parallel execution of queries)?

CREATE OR REPLACE PACKAGE TEST_VIEW AS
  FUNCTION get_date RETURN DATE;  
  
  FUNCTION set_date(i_mode NUMBER) RETURN NUMBER;
  
  FUNCTION several_select_from_same_view (
      i_date1 IN DATE
    , i_date2 IN DATE
  ) RETURN SYS_REFCURSOR;
END TEST_VIEW;
/

CREATE OR REPLACE VIEW V_TEST AS
  WITH params AS
         (SELECT TEST_VIEW.get_date one_day
            FROM DUAL
          )
     , cursor_emulation AS
         (
           SELECT TO_DATE('01-july-2016') one_day FROM DUAL
           UNION ALL
           SELECT TO_DATE('02-july-2016') one_day FROM DUAL
           UNION ALL
           SELECT TO_DATE('03-july-2016') one_day FROM DUAL
         )
      SELECT ce.*
        FROM cursor_emulation ce
           , params p
       WHERE ce.one_day = p.one_day;
       
CREATE OR REPLACE PACKAGE BODY TEST_VIEW AS
  g_date DATE;
  g_date1 DATE;
  g_date2 DATE;  

  FUNCTION get_date RETURN DATE IS
  BEGIN    
    RETURN g_date;
  END get_date;
  
  FUNCTION set_date(i_mode NUMBER) RETURN NUMBER IS
  BEGIN            
    IF i_mode = 1 THEN
      g_date := g_date1;
    ELSE
      g_date := g_date2;
    END IF;
    RETURN 1;
  END set_date;
  
  FUNCTION several_select_from_same_view (
      i_date1 IN DATE
    , i_date2 IN DATE
  ) RETURN SYS_REFCURSOR IS l_result SYS_REFCURSOR;
  BEGIN 
    g_date := NULL;
    g_date1 := i_date1;
    g_date2 := i_date2;
                    
    OPEN l_result FOR
      SELECT * FROM V_TEST WHERE SET_DATE(1) = 1
      UNION ALL                                  
      SELECT * FROM V_TEST WHERE SET_DATE(2) = 1;
      
    RETURN l_result;
  END several_select_from_same_view;
END TEST_VIEW;
/ 

SELECT TEST_VIEW.several_select_from_same_view(TO_DATE('01-july-2016'), TO_DATE('03-july-2016')) FROM DUAL

and Chris said...

It's certainly possible that you'll get some unexpected results with this method. If you place the (undocumented) materialize hint in the with clause, Oracle builds a temporary table to store the results.

Do this and you'll find Oracle sticks with one value:

CREATE OR REPLACE VIEW V_TEST AS
  WITH params AS
         (SELECT /*+ materialize */TEST_VIEW.get_date one_day
            FROM DUAL
          )
     , cursor_emulation AS
         (
           SELECT TO_DATE('01-july-2016') one_day FROM DUAL
           UNION ALL
           SELECT TO_DATE('02-july-2016') one_day FROM DUAL
           UNION ALL
           SELECT TO_DATE('03-july-2016') one_day FROM DUAL
         )
      SELECT ce.*
        FROM cursor_emulation ce
           , params p
       WHERE ce.one_day = p.one_day;

SELECT TEST_VIEW.several_select_from_same_view(
  TO_DATE('01-july-2016'), TO_DATE('02-july-2016')
) 
FROM DUAL;

TEST_VIEW.SEVERAL_SE
--------------------
CURSOR STATEMENT : 1

CURSOR STATEMENT : 1

ONE_DAY
---------
01-JUL-16


In complex queries it's you may get other transformations which result in things not working as expected. Particularly as 12c introduces concurrent union all execution. This enables all the branches to execute at the same time.

Rating

  (2 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

A reader, October 13, 2016 - 10:12 am UTC

Too bad that this method is not correct. I tried to avoid code duplication - request, decorated in a parameterized representation in a real application is not small (over 250 lines).

As a result, I need:

Either create another view. its code will be completely the same, only different is the name of a function that returns the value.

Or write a new select statement, about 500 lines, combining two very similar query, each of which does the same thing but for different values ​​of parameters.

In any case, thank you very much for your reply
Chris Saxon
October 13, 2016 - 2:44 pm UTC

Yes, you should look into another method. As Mike says below, just because it looks like Oracle will call the functions in a certain order, doesn't mean it will!

Don't depend on order of evaluation

Mike Tefft, October 13, 2016 - 11:27 am UTC

Your method seems to depend on set_date being executed before get_date.

There are very few cases in SQL where you can depend on order of execution - a CASE statement is the only example that comes to mind at the moment.

So I think the entire approach is based on an unwarranted assumption.
Chris Saxon
October 13, 2016 - 2:44 pm UTC

Great point.

More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library