sql >> データベース >  >> RDS >> PostgreSQL

複数の日付範囲を比較する

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

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

    提供されているすべての個人を確認します 日付範囲(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でテストされ、動作します。




    1. Oracle で列を行に変換する

    2. mysql変数でmysqlsourceコマンドを使用するにはどうすればよいですか?

    3. plsqlのプロシージャ本体内にカーソルを作成する方法

    4. mysql_fetch_arrayはすべての行を追加しますか?