Get distinct consecutive date ranges from overlapping date ranges Get distinct consecutive date ranges from overlapping date ranges sql sql

# Get distinct consecutive date ranges from overlapping date ranges

The logic is:

• at the beginning of an interval add its value to a cumulative sum
• at the end of an interval substract its value from this sum
• but in order to sweep the dateline, we'll have to collect al the (unique) date/time stamps, either start or stop.

So the point is: convert the data from a series of intervals to a series of (start/stop) events, and aggregate over these.

``-- \i tmp.sqlcreate table coinsonperiod(  id serial,  startdate date,  enddate date,  coins integer);insert into coinsonperiod (startdate, enddate, coins) values  ('2018-01-01','2018-01-31', 80), ('2018-01-07','2018-01-10', 10), ('2018-01-07','2018-01-31', 10), ('2018-01-11','2018-01-31', 5), ('2018-01-25','2018-01-27', 5), ('2018-02-02','2018-02-23', 100)        ;WITH changes AS (    SELECT startdate AS tickdate , coins            , 1 AS cover    FROM coinsonperiod    UNION ALL    -- add 1 day to convert to half-open intervals    SELECT 1+enddate AS tickdate, -1* coins            , -1 AS cover    FROM coinsonperiod    ), sumchanges  AS (        SELECT tickdate, SUM(coins) AS change, SUM(cover) AS cover        FROM changes        GROUP BY tickdate        ), aggregated AS (        SELECT        tickdate AS startdate        , lead(tickdate) over www AS enddate        , sum(change) OVER www AS cash          -- number of covered intervals        , sum(cover) OVER www AS cover        FROM sumchanges        WINDOW www AS (ORDER BY tickdate)        )             -- substract one day from enddate to correct back to closed intervalsSELECT startdate, enddate-1 AS enddate, cash, coverFROM aggregatedWHERE cover > 0ORDER BY startdate        ;``

Looks like I found an ugly one that works

``select t1.dt, t1.enddt, sum(coins)from (    select distinct cp1.dt, min(cp2.dt) enddt    from ( select startdate as dt from coinsonperiod union all select enddate as dt from coinsonperiod ) cp1,          ( select startdate as dt from coinsonperiod union all select enddate as dt from coinsonperiod ) cp2    where cp2.dt > cp1.dt    group by cp1.dt    order by cp1.dt ) t1, coinsonperiod t2where t1.dt between t2.startdate and t2.enddateand t1.enddt between t2.startdate and t2.enddategroup by t1.dt, t1.enddt``

Output:

``dt         |enddt      |sum |-----------|-----------|----|2018-01-01 |2018-01-07 |80  |2018-01-07 |2018-01-10 |100 |2018-01-10 |2018-01-11 |90  |2018-01-11 |2018-01-25 |95  |2018-01-25 |2018-01-27 |100 |2018-01-27 |2018-01-31 |95  |2018-02-02 |2018-02-23 |100 |``

Only difference with your output is that I suppose you forgot the interval between 01/10 and 01/11

Okay, so I'm going to help you with the logic bit, the syntax you can find online.

What you can do, is create a temp table and move you data there, then select each row of data and for each column data store the value in a declared variable.

Then simply use a cursor, and select all the data from your source table and again use a normal greater then or less than operator and work your way to get the count.

Simple get row 1 column 1, compare against all other column 1 and column 2 data.