比较多个日期范围

时间:2012-05-25 15:59:27

标签: sql postgresql jasper-reports ireport date-range

我正在使用iReport 3.0.0,PostgreSQL 9.1。对于报告,如果过滤器范围涵盖部分涵盖等,我需要将发票中的日期范围与过滤器中的日期范围进行比较并打印每个发票代码等。事情,每个发票代码可以有多个日期范围。

表发票

ID  Code    StartDate   EndDate
1   111     1.5.2012    31.5.2012
2   111     1.7.2012    20.7.2012
3   111     25.7.2012   31.7.2012
4   222     1.4.2012    15.4.2012
5   222     18.4.2012   30.4.2012

实施例

过滤器:1.5.2012。 - 5.6.2012。
我需要得到的结果是:

code 111 - partialy covered 
code 222 - invoice missing

过滤器:1.5.2012。 - 2012年5月31日。

code 111 - fully covered
code 222 - invoice missing

过滤器:1.6.2012。 - 2012年6月30日。

code 111 -  invoice missing
code 222 -  invoice missing

1 个答案:

答案 0 :(得分:2)

在评论中澄清。

我理解你的任务:

检查所有提供的个人日期范围(filter)是否包含在表格中组合日期范围的代码集中{({ {1}})。

可以使用纯SQL来完成,但不是一项简单的任务。步骤可以是:

  1. 将日期范围作为过滤器。

  2. 将每个代码的invoice表格中的日期范围合并。 每个代码可以产生一个或多个范围。

  3. 查找过滤器和合并发票之间的重叠

  4. 分类:完全覆盖/部分覆盖。 可以导致一次全覆盖,一次或两次部分覆盖或无覆盖。 降低到最高覆盖水平。

  5. 以合理的排序顺序显示(过滤器,代码)的每个组合的一行,以及合理的排序

  6. Ad hoc过滤器范围

    invoice

    将它们放在(临时)表中并改为使用该表。

    组合每个代码的重叠/相邻日期范围

    WITH filter(filter_id, startdate, enddate) AS (
        VALUES
          (1, '2012-05-01'::date, '2012-06-05'::date) -- list filters here.
         ,(2, '2012-05-01', '2012-05-31')
         ,(3, '2012-06-01', '2012-06-30')
        )
    SELECT * FROM filter;
    

    替代最终SELECT(可能更快或不更快,你必须测试):

    WITH a AS (
        SELECT code, startdate, enddate
              ,max(enddate) OVER (PARTITION BY code ORDER BY startdate) AS max_end
    -- Calculate the cumulative maximum end of the ranges sorted by start
        FROM   invoice
        ), b AS (
        SELECT *
              ,CASE WHEN lag(max_end) OVER (PARTITION BY code
                                            ORDER BY startdate) + 2 > startdate
    -- Compare to the cumulative maximum end of the last row.
    -- Only if there is a gap, start a new group. Therefore the + 2.
               THEN 0 ELSE 1 END AS step
        FROM   a
        ), c AS (
        SELECT code, startdate, enddate, max_end
              ,sum(step) OVER (PARTITION BY code ORDER BY startdate) AS grp
    -- Members of the same date range end up in the same grp
    -- If there is a gap, the grp number is incremented one step
        FROM   b
        )
    SELECT code, grp
          ,min(startdate) AS startdate
          ,max(enddate) AS enddate
    FROM   c
    GROUP  BY 1, 2
    ORDER  BY 1, 2
    

    合并到一个查询

    SELECT DISTINCT code, grp
              ,first_value(startdate) OVER w AS startdate
              ,last_value(enddate) OVER w AS enddate
    FROM   c
    WINDOW W AS (PARTITION BY code, grp ORDER BY startdate
                 RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) 
    ORDER  BY 1, 2;
    

    在PostgreSQL 9.1上测试并为我工作。