Retrieve Dates Between Two Dates
Bharath, March 06, 2002 - 12:31 pm UTC
How about this...
SELECT TO_DATE('01/01/2001','MM/DD/YYYY') + (ROWNUM - 1) DATEGEN
FROM ALL_OBJECTS
WHERE TO_DATE('01/01/2001','MM/DD/YYYY') + (ROWNUM - 1) <= TO_DATE('01/31/2002','MM/DD/YYYY')
;
March 06, 2002 - 12:58 pm UTC
if you factor that predicate so that ROWNUM is on the LHS by itself -- it'll be OK
rownum <= TO_DATE('01/31/2002','MM/DD/YYYY')-TO_DATE('01/01/2001','MM/DD/YYYY')+1
otherwise, it'll evaluate that for every row in all_objects -- not just the 31 you want.
SELECT TO_DATE('01/01/2001','MM/DD/YYYY') + (ROWNUM - 1) DATEGEN
FROM ALL_OBJECTS
WHERE TO_DATE('01/01/2001','MM/DD/YYYY') + (ROWNUM - 1) <=
TO_DATE('01/31/2002','MM/DD/YYYY')
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.02 0.03 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 28 0.74 0.72 0 14080 4 396
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 30 0.76 0.75 0 14080 4 396
SELECT TO_DATE('01/01/2001','MM/DD/YYYY') + (ROWNUM - 1) DATEGEN
FROM ALL_OBJECTS
WHERE
rownum <=
TO_DATE('01/31/2002','MM/DD/YYYY') - TO_DATE('01/01/2001','MM/DD/YYYY') + 1
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.02 0.02 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 28 0.10 0.08 0 1636 4 396
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 30 0.12 0.10 0 1636 4 396
Dates b/w two given dates ....
Priya, March 07, 2002 - 12:27 am UTC
Tom,
This is fine as long as the number of rows in DBA_objects or for that matter any other table or view may have sufficient rows as as to return the dates . In the case where the dates b/w 2 given dates may exceed the number of rows in for eg : DBA_OBJECTS , we have a problem . Do we have a fix for this ?
March 07, 2002 - 7:58 am UTC
if you need more then 2 to 3 years of dates generated -- (given that all objects in 73 is around 1000 rows and 20-30,000 for a java install in 8i), I question what you are doing. What would you do with 1,000 days in a list?
The solution of course would be for YOUR application to install and populate a table that is big enough for you. Part of your install would be:
create table rows ( x int );
begin
for i in 1 .. 1000000 -- or whatever
loop
insert into rows values ( i );
end loop;
commit;
end;
/
In 9i, we can use a pipelined PLSQL function to generate as many rows as you like on the fly. See
</code>
http://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:2270447621346 <code>
for an example of that.
Securtiy Implications
A reader, March 07, 2002 - 2:43 am UTC
Yesterday Eveing had a Long Argument with my friend when i told him this solution he was saying that a DBA in a Production environment will not give Rights to all_objects.
I Felt it was a Bit Crazy because AFAIK i know we wont have any security Implication on Giving access to all_objects.
What are your thoughts on this.
Thanks.
Best Regards,
Ganesh R
March 07, 2002 - 8:15 am UTC
A DBA in production doesn't have to give the rights -- select on all_objects is always granted to PUBLIC upon install. Many Many products will not work without it. It is called "the data dictionary".
This is in catalog.sql:
grant select on ALL_OBJECTS to PUBLIC with grant option
/
all of the ALL_* and USER_* views are selectable by PUBLIC (anyone with CREATE SESSION can see them)
Hopefully your friend is not a DBA for a production environment!
Generating Dates...
A reader, March 09, 2002 - 1:04 am UTC
Hi Tom,
Thanks for the earlier Response. I have another one for you. [This actuall was the Main thread of the previous discussion that i had posted]
I Usually use this Generate Dates for a varitey of purposes.
Select '01-jan-2001' + rownum from all_objects where rownum < 100;
The Above Query Generates 100 Dates..
Now i heard from people that instead of using the all_objects view u should create a Table that has 4000 Odd rows that we can use so that if all_objects Privs have been revoked then also u'r function will work.
IMHO ... I feel there is no penality in using all_objects for this purpose.
Your thoughts on these...
Regards,
Ganesh R
March 10, 2002 - 5:25 pm UTC
Read the above comments about all_objects and security.
If you every have a database where all_objects access has been revoked, you are in a database that is
o not supported by Oracle support in all likelyhood.
o won't support most any 3rd party application
ALL_OBJECTS is *always* granted select on to PUBLIC. If it isn't, the database is broken and needs to be fixed.
The very idea that accessing ALL_OBJECTS is a security "risk" is utter nonsense. I would be very interested in hearing from others who think otherwise AND WHY -- so I can correct their thinking.
Question
Florin, March 31, 2004 - 3:55 am UTC
Hi Tom,
I'd like to retrieve a list of dates between 2 given dates.
Ex:
Input: 20040331 and 20040325
Output:
20040325
20040326
20040327
20040328
20040329
20040330
20040331
Many thanks in advance,
March 31, 2004 - 8:43 am UTC
ok, I'd use BETWEEN then?
... .where column between :a and :b
Thanks
Florin, March 31, 2004 - 10:01 am UTC
Hi,
I don't have a table containing dates.
I'd like to retrieve a list of dates by giving 2 dates as an input (using dual or something like this).
March 31, 2004 - 10:38 am UTC
oh, you mean like the original answer above??
select to_date(your_start)+rownum-1
from all_objects
where rownum <= to_date(your_end)-to_date(your_start)+1
Brilliant !!!
Florin, March 31, 2004 - 11:09 am UTC
Thanks a lot!!!
Amazing, but...
Joe Khoobyar, June 14, 2005 - 4:28 pm UTC
Utterly amazing. I used to just do this in a stored procedure, now I'll use this instead. One issue w/ it though:
Let's say I have a rather complex query that joins to an inline view of the dates returned by the original answer to the original question: (select sysdate-30+(rownum-1) from all_objects where rownum <= 30 ... or some derivate thereof)
I'd like to explain plan (or just set autotrace on), but the system won't let me do so (it gives an ORA-01039). I'm assuming this is because the all_objects table obviously isn't in my schema, and I don't have permissions to run explain plan on it...
Is there a workaround for this? Or do have revert back to using the stored proc if I want to explain the query plan?
June 14, 2005 - 4:41 pm UTC
in 9ir2 and up, use
with as_many_rows_as_you_need
as
(select level l
from dual
connect by level <= :N )
select .....
from as_many_rows_as_you_need, .....
Generating Dummy Rows
A reader, June 14, 2005 - 6:39 pm UTC
Here is another technique I learnt on Asktom for generating rows from dual instead of all_objects
SQL> select rownum from (select null from dual group by cube(1,1));
ROWNUM
----------
1
2
3
4
SQL> select rownum from (select null from dual group by cube(1,1,1)) ;
ROWNUM
----------
1
2
3
4
5
6
7
8
SQL> l
1 select rownum from (select null from dual group by cube(1,1,1))
2* where rownum < 6
SQL> /
ROWNUM
----------
1
2
3
4
5
cube(1,1,1,1) for 16 or less
cube(1,1,1,1,1) for 32 or less
and so on
Alex, June 30, 2005 - 4:21 pm UTC
Hi Tom,
I was wondering the best way to write a query to select rows only where the date in my in coming parameter is 55 days apart from the column i'm checking. Right now I'm checking if they're equal.
So if I'm doing something like this:
cursor c1 is
select due_date
from t
where due_date = pdue_date;
I would like to change it to return only rows 55 days before or after the incoming date. I'm sure this is very simple but my brain is spent from a tough week.
I'm using 8.1.7. Thanks a lot.
June 30, 2005 - 4:48 pm UTC
isn't that just:
where due_date between pdue_date-55 and pdue_date+55;
Alex, July 05, 2005 - 3:04 pm UTC
Yeah that's all it was, thanks. I have another trickier problem now I'm hoping you can help with. This is also a cursor where I'm looking to see if my parameter date falls between two date columns, start_date and end_date. If it does not, check between possible_start and possible_end.
The problem is that the date columns can be null. So I think what's happening is I'm getting results back where these columns are null even though they don't fall in between my date criteria because if something's null, how can a date be between null and some date, right?
I thought about using nvl, but then I realized I would have to provide a bogus date to return because they are date columns. Thus influencing my results. My code looks like this:
cursor c1 is
select date_oid
from schedules
where pdate between start_date and end_date
or pdate between possible_start and possible_end;
So let's say my parameter is 03/07/2004. I would get two
rows back:
START_DAT END_DATE POSSIBLE_ POSSIBLE_
--------- --------- --------- ---------
28-JUN-05 15-NOV-03 15-NOV-06
07-MAR-04 08-MAR-04 07-MAR-04 08-MAR-04
Do you have any advice? Is my problem clear?
July 05, 2005 - 3:17 pm UTC
sorry, clear as mud -- no example to work with.
do you want start_date of null to be like "negative infinity"?? not sure why you put null in there if so.
Alex, July 05, 2005 - 3:32 pm UTC
Ok fair enough. Let me try something, isn't there a way to order nulls so they show up and the end of a result set?
I'm thinking maybe if I order my date columns in that manner
the row I'm looking for would be the first returned.
In other words flip flop the two rows I posted.
July 05, 2005 - 3:51 pm UTC
order by column NULLS FIRST;
order by column NULLS LAST;
Santosh Upadhyay, July 06, 2005 - 8:41 am UTC
Hi Tom,
The entire thread was very useful to me in writing a query. For the given data:
EMpno num1 num2
123 2004 2008
456 2005 2007
I need something like:
EMpno num1 num2
123 2004 2005
123 2005 2006
....
123 2007 2008
456 2005 2006
456 2006 2007
I tried many things but still missing out few rows. Need some expert help.
Thanks in advance.
Santosh.
July 06, 2005 - 9:00 am UTC
umm, I don't even know what I'm looking at here.
This is a little vague, don't you think?
A stab...
Philip Moore, July 06, 2005 - 10:17 am UTC
Hi Tom,
With your approval - I would like to take a stab at this teaser :)
I believe that what the submitter was requesting was to list single-year intervals one at a time for a given employee (although he is using NUMBER datatypes as a date (year) - a Tom Kyte no-no).
Here goes:
philip@ORA9iR2 -> DROP TABLE tester
2 /
Table dropped.
philip@ORA9iR2 ->
philip@ORA9iR2 -> CREATE TABLE tester
2 ( empno INT
3 , num1 INT
4 , num2 INT
5 , CONSTRAINT tester_pk PRIMARY KEY (empno)
6 )
7 /
Table created.
philip@ORA9iR2 ->
philip@ORA9iR2 -> INSERT INTO tester (empno, num1, num2)
2 VALUES (123, 2004, 2008)
3 /
1 row created.
philip@ORA9iR2 ->
philip@ORA9iR2 -> INSERT INTO tester (empno, num1, num2)
2 VALUES (456, 2005, 2007)
3 /
1 row created.
philip@ORA9iR2 ->
philip@ORA9iR2 -> SELECT empno
2 , num1 + (lvl - 1) AS num1
3 , num1 + lvl AS num2
4 FROM tester
5 , (SELECT LEVEL AS lvl
6 FROM dual
7 CONNECT BY LEVEL < 9999
8 ) cart
9 WHERE cart.lvl <= (tester.num2 - tester.num1)
10 ORDER BY tester.empno
11 , cart.lvl
12 /
EMPNO NUM1 NUM2
---------- ---------- ----------
123 2004 2005
123 2005 2006
123 2006 2007
123 2007 2008
456 2005 2006
456 2006 2007
6 rows selected.
--
Hope this was helpful...
Thanks.
Sincerely,
Philip Moore
A reader, July 11, 2005 - 3:38 am UTC
APologies for psoting the question not so clear. I tried the solution suggested by Philip but I am getting the error ORA-01436. SHould there be a 'start with'?
Many thanks,
Santosh.
July 11, 2005 - 8:34 am UTC
the dual trick to generate rows only works in software written this century, eg: 9ir2 and above.