Reputation: 1
I have the following table of rates for given date range.
I want to write a sql query (PostgreSQL) to get the sum of prices for a give period if it's a continuous period..for example:
if I specify 2011-05-02 to 2011-05-09 on the first set the sum of the 6 rows should be returned,
but
if i specify 2011-05-02 to 2011-05-011 on the second set nothing should be returned.
My problem is that I don't know how to determine if a date range is continuous...can you please help? Thanks a lot
case 1: sum expected
price from_date to_date
------ ------------ ------------
1.0 "2011-05-02" "2011-05-02"
2.0 "2011-05-03" "2011-05-03"
3.0 "2011-05-04" "2011-05-05"
4.0 "2011-05-05" "2011-05-06"
5.0 "2011-05-06" "2011-05-07"
4.0 "2011-05-08" "2011-05-09"
case 2: no results expected
price from_date to_date
------ ------------ ------------
1.0 "2011-05-02" "2011-05-02"
2.0 "2011-05-03" "2011-05-03"
3.0 "2011-05-07" "2011-05-09"
4.0 "2011-05-09" "2011-05-011"
I do not have overlapping rates date ranges.
Upvotes: 0
Views: 1728
Reputation: 78523
I think you need to combine window functions and CTEs:
WITH
raw_rows AS (
SELECT your_table.*,
lag(to_date) OVER w as prev_date,
lead(from_date) OVER w as next_date
FROM your_table
WHERE ...
WINDOW w as (ORDER by from_date, to_date)
)
SELECT sum(stuff)
FROM raw_rows
HAVING bool_and(prev_date >= from_date - interval '1 day' AND
next_date <= to_date + interval '1 day');
http://www.postgresql.org/docs/9.0/static/tutorial-window.html
http://www.postgresql.org/docs/9.0/static/queries-with.html
Upvotes: 0
Reputation:
Not sure I understood the question completely, but what about this:
select *
from prices
where not exists (
select 1 from (
select from_date - lag(to_date) over (partition by null order by from_date asc) as days_diff
from prices
where from_date >= DATE '2011-05-01'
and to_date < DATE '2011-07-01'
) t
where coalesce(days_diff, 0) > 1
)
order by from_date
Upvotes: 1
Reputation: 11581
Here's a rather fonky way to solve it :
WITH RECURSIVE t AS (
SELECT * FROM d WHERE '2011-05-02' BETWEEN start_date AND end_date
UNION ALL
SELECT d.* FROM t JOIN d ON (d.key=t.key AND d.start_date=t.end_date+'1 DAY'::INTERVAL)
WHERE d.start_date <= '2011-05-09')
SELECT sum(price), min(start_date), max(end_date)
FROM t
HAVING min(start_date) <= '2011-05-02' AND max(end_date)>= '2011-05-09';
Upvotes: 0