2011-05-05 114 views
0

我有给定日期范围的以下费率表。PostgreSQL多个日期范围的价格

我想写一个SQL查询(PostgreSQL的),以获得价格的总和对于给定的时间段,如果它是一个连续period..for例如:如果我指定到2011-05-02 2011-05

-09第一组应当归还的6行的总和,

,如果我在第二组没有应返回指定2011-05-02至2011-05-011。

我的问题是,我不知道如何确定一个日期范围是否连续......你能帮忙吗?非常感谢

的情况下1:总和预计

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" 

案例2:没有结果预计

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" 

我没有重叠率的日期范围。

+0

为什么是第一个例子不断?价格5.0在2011-05-07结束,接下来的两天开始两天后? – 2011-05-05 12:14:59

+0

对不起我的坏...修正了它 – Rob 2011-05-05 12:53:41

+0

如果你在第一组中指定'2011-05-02'到'2011-05-11'怎么办(假设'(4.0“2011-05-08” “2011-05-09”)')?它是否应该返回“2011-05-02”到“2011-05-09”的结果? – 2011-05-05 13:06:08

回答

0

要获得价格的总和:

select sum(price) 
from your_table 
where .. checking to and from dates .. 
having param_dateend - param_datestart = sum(to_date - from_date) 

然而,必须保证该时段不重叠。如果他们这样做,查询将不会返回正确的结果。

您还需要自己计算日期检查 - 我不确定如果enddate或startdate处于某条记录的中间(记录的to_date和from_date之间),应该发生什么情况。将需要改变,如果你需要包括这样的情况:

having param_dateend - param_datestart = sum(
    case when to_date > param_dateend then param_dateend else to_date end 
    - 
    case when from_date < param_datestart then param_datestart else from_date end 
) 
+0

非常感谢......期间不重叠......无论结束日期的持续时间是什么时候都没有关系......我会尝试查询。 – Rob 2011-05-05 12:57:53

+0

@Rob给你一个例子 - 在你的第二种情况下,你有一段“2011-05-09”“2011-05-011”'如果你的结束日期是'2011-05-10' ?您还可以在表格中使用“2011-05-05”“2011-05-011”',并寻找'2011-05-07'和'2011-05-08'之间的价格? – Jakub 2011-05-05 13:00:56

+0

这个查询的另一个问题是Andriy M正确地指出了什么 - 如果您想要在未被数据覆盖的时期内获得价格,该怎么办? – Jakub 2011-05-05 13:21:22

1

不知道我完全理解的问题,但对于这一点:

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 
0

下面就来解决它,而fonky方式:

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'; 
0

我认为你需要结合窗口功能和热膨胀系数:

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