Skip to Main Content
  • Questions
  • Time periods determined from input user dates and table defined periods

Breadcrumb

Question and Answer

Chris Saxon

Thanks for the question, Emanuel.

Asked: August 06, 2018 - 4:54 pm UTC

Last updated: August 07, 2018 - 3:30 pm UTC

Version: 11

Viewed 1000+ times

You Asked

Hi,

I have a procedure that takes 2 parameters (start and end date) and using some additional data from a "settings" table and some sales transactions, populates an intermediary table.

The settings table was initially as 1 interval / 1 set of data but now there are more intervals, with different settings.

My problem is that starting with the user dates (start and end date) I need to determine from the settings table, all the intervals contained between them, so then I will call the procedure multiple times with all the intervals found.

To be precise, for the given example, if the user is using 01-Jan-2018 and 31-Jul-2018 I need to call the procedure using the following sets of dates:

01-Jan-2018 - 31-Mar-2018
01-Apr-2018 - 31-May-2018
01-Jun-2018 - 30-Jun-2018
01-Jul-2018 - 31-Jul-2018


I can determine the first and the last interval but I don't know how to deal with the middle part where can be two like in the exemple or more, depending on the input dates.

Thank you for any help!

with LiveSQL Test Case:

and Chris said...

So you're looking for intervals that:

- Start before and end after your start date
- Start before and end after your end date
- Start on or after your start date and end on or before your end date

And for intervals that start or end outside your range, you want to show your range instead?

If so, just put these tests in your where clause. And return the greatest of the row start + variable start. With the least of the row end + variable end.

Which gives:

CREATE TABLE F500 ( 
  ID          NUMBER(11)                        NOT NULL, 
  TARIF_1     FLOAT(126)                        NOT NULL, 
  DATA_START  DATE                              NOT NULL, 
  DATA_END    DATE                              NOT NULL 
);

Insert into F500 Values   (0, 0, TO_DATE('01/04/2016', 'DD/MM/YYYY'), TO_DATE('31/03/2017', 'DD/MM/YYYY'));
Insert into F500 Values   (1, 1, TO_DATE('01/04/2017', 'DD/MM/YYYY'), TO_DATE('31/03/2018', 'DD/MM/YYYY'));
Insert into F500 Values   (2, 2, TO_DATE('01/04/2018', 'DD/MM/YYYY'), TO_DATE('31/05/2018', 'DD/MM/YYYY'));
Insert into F500 Values   (3, 3, TO_DATE('01/06/2018', 'DD/MM/YYYY'), TO_DATE('30/06/2018', 'DD/MM/YYYY'));
Insert into F500 Values   (4, 4, TO_DATE('01/07/2018', 'DD/MM/YYYY'), TO_DATE('31/12/2019', 'DD/MM/YYYY'));
Insert into F500 Values   (5, 5, TO_DATE('01/01/2020', 'DD/MM/YYYY'), TO_DATE('31/12/2020', 'DD/MM/YYYY'));
Insert into F500 Values   (6, 6, TO_DATE('01/04/2016', 'DD/MM/YYYY'), TO_DATE('31/12/2020', 'DD/MM/YYYY'));

var start_date varchar2(20);
var end_date varchar2(20);

exec :start_date := '01-JAN-2018';
exec :end_date := '31-JUL-2018';

select id, tarif_1, 
       greatest ( data_start,  to_date ( :start_date, 'dd-mon-yyyy' ) ) start_date,
       least ( data_end,  to_date ( :end_date, 'dd-mon-yyyy' ) ) end_date
from   f500
where  ( 
  data_start < to_date ( :start_date, 'dd-mon-yyyy' ) and    
  data_end  >= to_date ( :start_date, 'dd-mon-yyyy' )
) or ( 
  data_start >= to_date ( :start_date, 'dd-mon-yyyy' ) and    
  data_end   <= to_date ( :end_date, 'dd-mon-yyyy' )
) or ( 
  data_start <  to_date ( :end_date, 'dd-mon-yyyy' ) and    
  data_end   >= to_date ( :end_date, 'dd-mon-yyyy' )
) ;

ID   TARIF_1   START_DATE             END_DATE               
   1         1 01-JAN-2018 00:00:00   31-MAR-2018 00:00:00   
   2         2 01-APR-2018 00:00:00   31-MAY-2018 00:00:00   
   3         3 01-JUN-2018 00:00:00   30-JUN-2018 00:00:00   
   4         4 01-JUL-2018 00:00:00   31-JUL-2018 00:00:00   
   6         6 01-JAN-2018 00:00:00   31-JUL-2018 00:00:00   


But beware!

Date ranges are tricky things. There are 13 ways you can classify how two date ranges overlap. This works for the data you provided. Plus a couple more I threw in.

Ensure you've covered off all possibilities. Or you're likely to end up with bugs!

Stew Ashton has several articles discussing this, I recommend you read them: https://stewashton.wordpress.com/2015/06/08/merging-overlapping-date-ranges/

Rating

  (1 rating)

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

Comments

Thank you for your answer!

Emanuel, August 07, 2018 - 2:01 pm UTC

Hi,

Your exemple is just perfect in it's simplicity :)

I know that the range intervals are tricky but because I "know" that there are no gaps between them and user dates are always inside them, I don't think that could cause further problems but thanks for the warning.
Chris Saxon
August 07, 2018 - 3:30 pm UTC

Thanks. I'd still test all the possible edge cases. Just to be sure ;)

More to Explore

SQL

The Oracle documentation contains a complete SQL reference.