Skip to Main Content
  • Questions
  • returning a series of values based on a start and end value using SQL

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Kari.

Asked: October 05, 2003 - 11:02 pm UTC

Last updated: March 08, 2005 - 7:59 am UTC

Version: 9.0.2

Viewed 1000+ times

You Asked

Hi,

is it possible to generate the following using sql: given e.g. two dates, sql would return one date for each month.

So, given 1-1-2000 and 31-12-2000 the query would return

1-1-2000
1-2-2000
1-3-2000
....
1-11-2000
1-12-2000

Using numbers, the same could be : given 1 and 10 the query would return 1,2,3,4,5,6,7,8,9,10.



TIA,
Kari


and Tom said...

ops$tkyte@ORA920> select add_months( to_date(:a,'dd-mm-yyyy'), rownum-1)
2 from all_objects
3 where rownum <=
4 months_between(to_date(:b,'dd-mm-yyyy'),to_date(:a,'dd-mm-yyyy'))+1
5 /

ADD_MONTH
---------
01-JAN-00
01-FEB-00
01-MAR-00
01-APR-00
01-MAY-00
01-JUN-00
01-JUL-00
01-AUG-00
01-SEP-00
01-OCT-00
01-NOV-00
01-DEC-00

12 rows selected.

ops$tkyte@ORA920>


Rating

  (16 ratings)

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

Comments

Pipelined Function

A reader, October 06, 2003 - 12:45 pm UTC

You can try Pipelined Function in Oracle 9i. It's very convenient.

Generate week days

Anil Pant, October 08, 2003 - 1:33 am UTC

If I wish to generate all the week days (mon to fri) one way is to by querying user_objects. Some like this

select to_char(to_date('01-jan-2003') + rownum,'day') , to_date('01-jan-2003') + rownum from user_objects
where rownum <= 365
and to_char(to_date('01-jan-2003') + rownum,'day') not in ('sunday', 'saturday')

Is there any other way to get the result without using user_objects or any intermediate table ?

Tom Kyte
October 08, 2003 - 6:48 am UTC


search this site for

pipelined


and see how you can write a pipelined function to do this. You'll query a plsql function as if it were a table

However, if you want to do it "right" (eg: easy, fast enough, simple), you'll use all_objects or some related table.

Mikito Harakiri, October 09, 2003 - 2:45 pm UTC

But all_objects is not a table, it's a obscenely complicated view!

Pipelined function or parametrized view is the clean way to solve this.

Tom Kyte
October 09, 2003 - 6:54 pm UTC

hey mikitto -- so, define and demonstrate for us this "parametrized view" concept?

(i do believe I said "some related table", all_objects works for many things just dandy)



Alternative to all_objects

Gary, October 09, 2003 - 8:31 pm UTC

In a simple test in Oracle9i, using a type constructor seems to work a lot quicker than using all_objects.
It also looks 'tidier' to me. [I don't want anything from all_objects, so I don't want to reference it]

create type year IS varray(366) of number(3) not null;

select sysdate+rownum
from
all_objects

call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 300.00 1953.13 0 0 0 0
Execute 1 0.00 3.76 0 0 0 0
Fetch 381 19800.00 18687.22 0 117861 0 5699
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 383 20100.00 20644.11 0 117861 0 5699

select sysdate+rownum
from table(year(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25)) a,
table(year(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25)) b,
table(year(1,2,3,4,5,6,7,8,9)) c

call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 100.00 54.76 0 0 0 0
Execute 1 0.00 1.21 0 0 0 0
Fetch 376 200.00 446.62 0 0 0 5625
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 378 300.00 502.59 0 0 0 5625



Tom Kyte
October 10, 2003 - 7:54 am UTC

gosh -- I hope you are using 8i tkprof on 9i traces :) else those runtimes are horrible.


but concurr -- that'll perform better.

Mikito Harakiri, October 09, 2003 - 10:00 pm UTC

Parametrized view is a synomym for table function.

As far as the performance concerned this is not even a competition:

SQL> CREATE TYPE IntSet AS TABLE OF Integer;
  2  /

SQL> CREATE or replace FUNCTION UNSAFE
  2    RETURN  IntSet PIPELINED IS
  3  BEGIN
  4      loop
  5         PIPE ROW(1);
  6      end loop;
  7  END;
  8  /

Function created.

SQL> set autotrace traceonly;
SQL> set timing on;
SQL> select count(1) from table(unsafe) 
where rownum < 1000000;

  COUNT(1)
----------
    999999

Elapsed: 00:00:01.08

         95  consistent gets
          2  physical reads

SQL> select count(1) from all_objects where rownum < 1000000;

  COUNT(1)
----------
    322153

Elapsed: 00:03:21.02

     608806  consistent gets
       7645  physical reads

2 problems with the actual view: 
1. It is unable to give me the full list of 1000000 numbers, as there are only 322K objects in the database.
2. You can't possibly beat 95 buffer gets for table fiunction. 

If there were no sorting involved, that is if I just wanted the list of million numbers back, the difference would be even more dramatic. 

Tom Kyte
October 10, 2003 - 7:57 am UTC

parameterize view might be YOUR synonym for that but I've never heard anyone else refer to it that way. To me a parameterize view is:


create or replace view V
as
select ....
where c1 = sys_context( 'my_ctx', 'c1' )
and c2 like sys_context( 'my_ctx', 'c2' )


then you use dbms_session.set_context to set the parameters to the view and select from it.


In any case, you'll find the approach one up from here to be many times more efficient then piping for doing this.


And remember -- we are hardly ever (like I mean never) using this techinque for thousands of records. Look at the original question and don't lose sight of that. People are asking for dozens of rows -- not millions, not hundreds of thousands, in these cases.

Mikito Harakiri, October 10, 2003 - 12:36 pm UTC

They are the synomyms. When googling "parameterized view table function" I see that the context is mostly SQL Server.

Of course you realize how goofy passing parameters to a view through the context is. Table function allows embedding the view and pass parameters into the view definition as host variables.

From engineer perspective there is a difference between 10 and 10000. From matematician's there isn't.

Tom Kyte
October 10, 2003 - 12:53 pm UTC

hmm, goofy.

I'll show you how goofy it is when it makes a view run 50,000 times faster then without. its not goofy, its very very useful at times. sometimes you need a predicate pushed down into the view to get the right semantics and performance.

you can call it what you want.


Totally agree with Tom

gs, October 10, 2003 - 2:49 pm UTC

We have a few views doing excelent using this technique. They could also be used as, sort of VPD, in the SE.

Parametrized views?

A reader, July 18, 2004 - 10:19 am UTC

"create or replace view V
as
select ....
where c1 = sys_context( 'my_ctx', 'c1' )
and c2 like sys_context( 'my_ctx', 'c2' )"

I dont understand this. What is the difference between this and

create or replace view v as select c1,c2,....

and then a query like

select ... from V where c1=:b1 and c2=:v2

i.e. just expose c1 and c2 in the view and use it as usual with regular bind variables.

What does the sys_context stuff buy us here?

Thanks



Tom Kyte
July 18, 2004 - 12:28 pm UTC

there are certain cases where it is useful.

like access control.
like pushing predicates way down into a view.
like environments where the query is already written and you just want to filter it a little (eg: you cannot change the sql, but you can create a view they query instead of the table)

it is just a technique.

Thanks

A reader, July 18, 2004 - 12:49 pm UTC

Great, didnt think about all the situations you pointed out.

Now that you mention it, I can think of many cases where I would want to push the predicates way down into the view and just exposing the columns in the view might not work if the view is joined with few other things, aggregated, etc.

You are absolutely right, as usual. Thanks.

When is context evaluated?

A reader, July 18, 2004 - 1:30 pm UTC

One more question: In the view

create or replace view V
as
select ....
where c1 = sys_context( 'my_ctx', 'c1' )


The sys_context is treated like a bind variable so the query is not hard-parsed every time it is encountered.

But if I do

exec dbms_session.set_context('my_ctx,'c1','aaa')
select * from v;

exec dbms_session.set_context('my_ctx,'c1','bbb')
select * from v;

Since the query is not hard parsed the second time around, when/where is the sys_context evaluated. It has to be evaluated for every execution of the query otherwise the result might be wrong.

Thanks

Tom Kyte
July 18, 2004 - 2:52 pm UTC

sys_context is evaluated during the "open" phase of the query -- it'll do what you expect it to do -- each of those queries will see a different sys context value

Set up - parameterize view

JEOM, February 16, 2005 - 12:52 pm UTC

What do I need to set up a parameterize view, I mean:
Grants needs to execute it
Do I have to create a context per view?
Can you share us an example step by step.

Tom Kyte
February 16, 2005 - 2:39 pm UTC

nothing different from a regular view.

you can use one or a thousand application contexts, that is up to you.

grant as you would grant on any other view. nothing special here.

???

JEOM, February 16, 2005 - 3:43 pm UTC

I can create the view as follow:

CREATE TABLE T1(col1 INT, col2 INT);
INSERT INTO T1 VALUES(1,2);
INSERT INTO T1 VALUES(3,4);
INSERT INTO T1 VALUES(5,6);
INSERT INTO T1 VALUES(7,8);
COMMIT;
CREATE OR REPLACE VIEW PV_T1 AS
SELECT col2 FROM T1
WHERE col1 = sys_context('ctx','col1');
--but what privileges do I need??
u01@VENUS> EXEC dbms_session.set_context('ctx','col1','3');
BEGIN dbms_session.set_context('ctx','col1','3'); END;
*
ERROR at line 1:
ORA-01031: insufficient privileges
ORA-06512: at "SYS.DBMS_SESSION", line 78
ORA-06512: at line 1

Tom Kyte
February 16, 2005 - 5:19 pm UTC

a context many only be set by a trusted piece of code.

when you created the context, you

create context ctx using SOME_PACKAGE_OR_PROCEDURE
/

only that package or procedure, which you write, you secure, is able to set the context. IT can call dbms_session to set a context value, after validating that user calling it is supposed to be able to.

Review

JEOM, February 16, 2005 - 5:36 pm UTC

I have created a code to call dbms_session.set_context, and now it works.

CREATE OR REPLACE PACKAGE BNFPUBLIC.PKG_EXECUTE
AUTHID CURRENT_USER AS
PROCEDURE SP_CONTEXT
( pcolumn IN VARCHAR2,
pvalue IN VARCHAR2
);
END PKG_EXECUTE;
/

CREATE OR REPLACE PACKAGE BODY BNFPUBLIC.PKG_EXECUTE
AS
PROCEDURE SP_CONTEXT
( pcolumn IN VARCHAR2,
pvalue IN VARCHAR2
) AS
BEGIN
dbms_session.set_context('CTX', pcolumn, pvalue);
END SP_CONTEXT;
END PKG_EXECUTE;
/

u01@VENUS> EXEC pkg_execute.sp_context('col1', 3);
u01@VENUS> SELECT * FROM u01.pv_t1;
COL2
----------
6

...If it is like a bind variable, it'll use the pk or idx as well???

Tom Kyte
February 16, 2005 - 5:41 pm UTC

bind variables do not preclude indexes, it'll use indexes as before.

Thanks

JEOM, February 16, 2005 - 6:10 pm UTC

right :)

Which one then?

Gabriel, March 07, 2005 - 11:48 am UTC

Hello Tom,

Which option would you choose and why in an environment where hundreds of users will need different result sets based on different parameters passed by in each session:

parametrized views?
pipelined funstions?
pl/sql in global temporary tables?

(ref cursors or arrays of records are out of the question due to third party software limitations).
The result sets should be in the hundreds of rows not more than that.

Thank you very much for your response and for the amazing site,

Tom Kyte
March 07, 2005 - 7:50 pm UTC

more details, how many queries (select lists -- not predicates) are we talking.



Select lists

Gabriel, March 07, 2005 - 9:30 pm UTC

Hello Tom,

We will only select 3 fields, 10,20 and 45 varchar2 fields.

Thank you,

Tom Kyte
March 08, 2005 - 7:59 am UTC

I would be up for trying a pipelined function then -- create the type and


select *
from table( cast(my_function( <arguments to build where clause> ) as mytype) )


Using application contexts (sys_context) to "bind" the where clause