2

iReport 3.0.0、PostgreSQL9.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。--31.5.2012。

code 111 - fully covered
code 222 - invoice missing

フィルタ:1.6.2012。--30.6.2012。

code 111 -  invoice missing
code 222 -  invoice missing
4

1 に答える 1

4

コメントで明確にした後。

私が理解しているあなたの仕事:

提供されているすべての個別の日付範囲( )をチェックして、それらがテーブル内のコードセットの結合filterされた日付範囲( )でカバーされているかどうかを確認します。invoice

プレーンSQLで実行できますが、簡単な作業ではありません。手順は次のとおりです。

  1. フィルタとして日付範囲を指定します。

  2. invoiceコードごとにテーブルの日付範囲を組み合わせます。コードごとに1つ以上の範囲になる可能性があります。

  3. フィルタと結合された請求書の間の重複を探します

  4. 分類:完全にカバーされている/部分的にカバーされている。1つの完全なカバレッジ、1つまたは2つの部分的なカバレッジ、またはカバレッジなしになる可能性があります。カバレッジの最大レベルに減らします。

  5. (フィルター、コード)と結果のカバレッジの組み合わせごとに、適切な並べ替え順序で1行を表示します

アドホックフィルター範囲

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;

または、それらを(一時的な)テーブルに入れて、代わりにそのテーブルを使用します。

コードごとに重複/隣接する日付範囲を組み合わせる

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(高速かどうかは別として、テストする必要があります):

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;

1つのクエリに結合

WITH 
    -- supply one or more filter values
    filter(filter_id, startdate, enddate) AS (
    VALUES
      (1, '2012-05-01'::date, '2012-06-05'::date) -- cast values in first row
     ,(2, '2012-05-01', '2012-05-31')
     ,(3, '2012-06-01', '2012-06-30')
    )
    -- combine date ranges per code
    ,a AS (
    SELECT code, startdate, enddate
          ,max(enddate) OVER (PARTITION BY code ORDER BY startdate) AS max_end
    FROM   invoice
    ), b AS (
    SELECT *
          ,CASE WHEN (lag(max_end) OVER (PARTITION BY code ORDER BY startdate)
                      + 2) > startdate 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
    FROM   b
    ), i AS ( -- substitutes original invoice table
    SELECT code, grp
          ,min(startdate) AS startdate
          ,max(enddate) AS enddate
    FROM   c
    GROUP  BY 1, 2
    )
    -- match filters
    , x AS (
    SELECT f.filter_id, i.code
            ,bool_or(f.startdate >= i.startdate
              AND f.enddate   <= i.enddate) AS full_cover
    FROM   filter f
    JOIN   i ON i.enddate >= f.startdate
            AND i.startdate <= f.enddate -- only overlapping
    GROUP  BY 1,2
    )
SELECT f.*, i.code
      ,CASE x.full_cover
        WHEN TRUE  THEN 'fully covered'
        WHEN FALSE THEN 'partially covered'
        ELSE            'invoice missing'
       END AS covered
FROM   (SELECT DISTINCT code FROM i) i
CROSS  JOIN filter f -- all combinations of filter and code
LEFT   JOIN x USING (filter_id, code)    -- join in overlapping
ORDER  BY filter_id, code;

PostgreSQL 9.1でテストされ、動作します。

于 2012-05-26T19:43:34.663 に答える