选择日期范围而不重叠

时间:2016-01-07 17:24:56

标签: sql postgresql date-range

我有以下关系模式:

dates(date: date, code: char)

代码可以是ST,MN,MX,ED。 一个例子:

╔════════════╦══════╗
║    date    ║ code ║
╠════════════╬══════╣
║ 2001-10-01 ║ ST   ║
║ 2001-10-20 ║ ST   ║
║ 2001-11-01 ║ MX   ║
║ 2001-11-01 ║ MN   ║
║ 2001-11-14 ║ MX   ║
║ 2001-11-15 ║ ED   ║
║ 2001-11-15 ║ MX   ║
║ 2001-11-27 ║ MN   ║
║ 2001-12-01 ║ ST   ║
║ 2001-12-01 ║ ED   ║
║ 2001-12-02 ║ MX   ║
║ 2001-12-03 ║ MX   ║
║ 2001-12-05 ║ ED   ║
║ 2001-12-20 ║ ST   ║
║ 2001-12-21 ║ MN   ║
║ 2001-12-24 ║ MX   ║
║ 2001-12-31 ║ ED   ║
╚════════════╩══════╝

我需要:

  1. 查找以ST为代码开头的任何日期范围,以以ED为代码的日期结束。
  2. 在这些范围内,不能有任何以ST或ED作为代码的元组(范围不能重叠)。
  3. 没有程序,只有一个SELECT语句(我可以使用WITH)。
  4. 我使用以下查询做了第一部分:

    SELECT DISTINCT ON (dt.date) dt.date AS start, dt1.date AS end
    FROM dates AS dt, dates AS dt1
    WHERE dt.type='ST' AND dt1.type='ED' AND dt.date<dt1.date;
    

    我无法弄清楚如何消除重叠范围。 使用给定的示例数据,我的查询输出:

    ╔════════════╦════════════╗
    ║   start    ║    end     ║
    ╠════════════╬════════════╣
    ║ 2001-10-01 ║ 2001-12-01 ║
    ║ 2001-10-20 ║ 2001-11-15 ║
    ║ 2001-12-01 ║ 2001-12-31 ║
    ║ 2001-12-20 ║ 2001-12-31 ║
    ╚════════════╩════════════╝
    

    正如您所看到的那样,第二个范围与第一个范围重叠,因此它无法正常工作。

    正确的输出应该是:

    ╔════════════╦════════════╗
    ║   start    ║    end     ║
    ╠════════════╬════════════╣
    ║ 2001-10-20 ║ 2001-11-15 ║
    ║ 2001-12-20 ║ 2001-12-31 ║
    ╚════════════╩════════════╝
    

1 个答案:

答案 0 :(得分:2)

如果我理解正确,那么您可以将lead()where用于此目的:

select date as startdate, next_date as enddate
from (select d.*,
             lead(code) over (order by date) as next_code,
             lead(date) over (order by date) as next_date
      from dates d
      where code in ('ST', 'ED')
     ) d
where code = 'ST' and
      next_code = 'ED';