Oracle FAQ | Your Portal to the Oracle Knowledge Grid |
Home -> Community -> Usenet -> c.d.o.server -> Re: show all values between X and Y
rob wrote:
> Stacy Y wrote:
>
>> Hi there, >> >> I am working on a reporting project where all datefields have been set >> as varchar2 fields, so computations on dates are proving to be quite >> tricky. >> >> I have a create date and a completion date, and I need to find the >> number of days between those two dates, not including off days >> (weekends and holidays). The weekend and holiday dates are stored in a >> separate table, so I can reference back to them (i.e: NOT IN (SELECT * >> FROM TABLE). >> >> Can anyone help me with the way this statement would look? I'm stuck. >> This is the line for what I have so far - I don't know how to >> incorporate that reference into it... >> >> SELECT >> SUBSTR(CAD.AEVEN.XDTS,-16,8)-SUBSTR(CAD.AEVEN.CREATE_DATETIME,-16,8) AS >> ELAPSED_DAYS >> >> Thanks! >> Stacy >>
/*
|| holiday_table holds the dates to be excluded from the interval
calculation
*/
CREATE TABLE holiday_table
( holiday_date DATE )
/*
|| Inserted 12/31/02, 1/1/03, 2/17/03, 5/26/03, 7/4/03, 9/1/03, 11/27/03,
|| 11/28/03, 12/24/03, 12/25/03, 12/31/03, and 1/1/04 into holiday_table
*/
CREATE TABLE test_interval
( start_date DATE,
end_date DATE
)
/*
|| Inserted 500 rows into test_interval, with dates ranging from 12/02
into 5/04
|| Tested intervals ranged from 1 day apart to beyond 1 year apart
*/
/*
|| The PL/SQL implementation of the business day logic
*/
CREATE OR REPLACE FUNCTION busdays_between
( p_start_dt DATE,
p_end_dt DATE )
RETURN NUMBER
IS
cln_start_dt DATE := TRUNC( p_start_dt ); cln_end_dt DATE := TRUNC( p_end_dt ); first_dt DATE; last_dt DATE; orientation PLS_INTEGER := 1; first_dowk PLS_INTEGER; count_first PLS_INTEGER := 1; last_dowk PLS_INTEGER; wks_btwn PLS_INTEGER;
first_dt := cln_start_dt; last_dt := cln_end_dt; ELSE first_dt := cln_end_dt; last_dt := cln_start_dt; orientation := -1;
INTO count_hdays FROM holiday_table WHERE holiday_date BETWEEN first_dt AND last_dt;first_dowk := TO_NUMBER( TO_CHAR( first_dt, 'D' ) ); last_dowk := TO_NUMBER( TO_CHAR( last_dt, 'D' ) ); wks_btwn := TRUNC( ( last_dt - first_dt ) / 7 ); IF first_dowk > last_dowk
sat_adjst := 1; count_first := 0;
( last_dowk - first_dowk + count_first ) + sat_adjst - count_hdays ) * orientation;
( SELECT * FROM test_interval ) LOOP SELECT COUNT( * ) INTO next_interval FROM ( SELECT ROWNUM - 1 rnum FROM ALL_OBJECTS WHERE ROWNUM <= date_rec.end_date - date_rec.start_date + 1 ) WHERE TO_CHAR( date_rec.start_date + rnum, 'DY' ) NOT IN ( 'SAT', 'SUN' ) AND NOT EXISTS ( SELECT NULL FROM holiday_table WHERE holiday_date = TRUNC( date_rec.start_date + rnum ) ); max_interval := GREATEST( next_interval, max_interval );END LOOP;
Elapsed: 00:00:27.89 */
/*
|| Same basic PL/SQL block as above, using function instead
*/
DECLARE
next_interval NUMBER;
max_interval NUMBER := 0;
BEGIN
FOR date_rec IN
( SELECT * FROM test_interval ) LOOP SELECT busdays_between( date_rec.start_date, date_rec.end_date ) INTO next_interval FROM DUAL; max_interval := GREATEST( next_interval, max_interval );END LOOP;
Elapsed: 00:00:00.21 */
/*
|| Showing dependence of performance upon interval length
*/
DECLARE
/*
|| One day interval
*/
date1 DATE := TO_DATE( '030102', 'YYMMDD' ); date2 DATE := TO_DATE( '030103', 'YYMMDD' );next_interval NUMBER;
SELECT busdays_between( date1, date2 ) INTO next_interval FROM DUAL;
date1 DATE := TO_DATE( '030102', 'YYMMDD' ); date2 DATE := TO_DATE( '040102', 'YYMMDD' );next_interval NUMBER;
SELECT busdays_between( date1, date2 ) INTO next_interval FROM DUAL;
date1 DATE := TO_DATE( '030102', 'YYMMDD' ); date2 DATE := TO_DATE( '030103', 'YYMMDD' );next_interval NUMBER;
SELECT COUNT( * ) INTO next_interval FROM ( SELECT ROWNUM - 1 rnum FROM ALL_OBJECTS WHERE ROWNUM <= date2 - date1 + 1 ) WHERE TO_CHAR( date1 + rnum, 'DY' ) NOT IN ( 'SAT', 'SUN' ) AND NOT EXISTS ( SELECT NULL FROM holiday_table WHERE holiday_date = TRUNC( date1 + rnum ) );
date1 DATE := TO_DATE( '030102', 'YYMMDD' ); date2 DATE := TO_DATE( '040102', 'YYMMDD' );next_interval NUMBER;
SELECT COUNT( * ) INTO next_interval FROM ( SELECT ROWNUM - 1 rnum FROM ALL_OBJECTS WHERE ROWNUM <= date2 - date1 + 1 ) WHERE TO_CHAR( date1 + rnum, 'DY' ) NOT IN ( 'SAT', 'SUN' ) AND NOT EXISTS ( SELECT NULL FROM holiday_table WHERE holiday_date = TRUNC( date1 + rnum ) );