Question

This is the result of one of my queries:

SURGERY_D
---------
01-APR-05
02-APR-05
03-APR-05
04-APR-05
05-APR-05
06-APR-05
07-APR-05

11-APR-05
12-APR-05
13-APR-05
14-APR-05
15-APR-05
16-APR-05

19-APR-05
20-APR-05
21-APR-05
22-APR-05
23-APR-05
24-APR-05

26-APR-05
27-APR-05
28-APR-05
29-APR-05
30-APR-05

I want to collapse the date ranges which are continuous, into intervals. For examples,

[01-APR-05, 07-APR-05], [11-APR-05, 16-APR-05] and so on.

In terms of temporal databases, I want to 'collapse' the dates. Any idea how to do that on Oracle? I am using version 11. I searched for it and read a book but couldn't find/understand how to do it. It might be simple, but everyone has their own flaws and Oracle is mine. Also, I am new to SO so my apologies if I have violated any rules. Thank You!

Was it helpful?

Solution

You can take advantage of the ROW_NUMBER analytical function to generate a unique, sequential number for each of the records (we'll assign that number to the dates in ascending order).

Then, you group the dates by difference between the date and the generated number - the consecutive dates will have the same difference:

Date       Number      Difference
01-APR-05       1               1      -- MIN(date_val) in group with diff. = 1
02-APR-05       2               1
03-APR-05       3               1
04-APR-05       4               1
05-APR-05       5               1
06-APR-05       6               1
07-APR-05       7               1      -- MAX(date_val) in group with diff. = 1
11-APR-05       8               3      -- MIN(date_val) in group with diff. = 3
12-APR-05       9               3
13-APR-05      10               3
14-APR-05      11               3
15-APR-05      12               3
16-APR-05      13               3      -- MAX(date_val) in group with diff. = 3

Finally, you select the minimal and maximal date in each of the groups to get the beginning and ending of each range.

Here's the query:

SELECT
    MIN(date_val) start_date,
    MAX(date_val) end_date
  FROM (
    SELECT
        date_val,
        row_number() OVER (ORDER BY date_val) AS rn
      FROM date_tab
  )
GROUP BY date_val - rn
ORDER BY 1
;

Output:

START_DATE   END_DATE 
------------ ----------
01-04-2005   07-04-2005 
11-04-2005   16-04-2005 
19-04-2005   24-04-2005 
26-04-2005   30-04-2005

You can check how that works on SQLFidlle: Dates ranges example

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top