sql >> Databáze >  >> RDS >> PostgreSQL

Porovnejte více časových období

Po upřesnění v komentáři.

Váš úkol, jak ho chápu já:

Zkontrolujte všechny dodané jednotlivce rozsahy dat (filter ), zda jsou zahrnuty pod kombinované časové rozsahy sad kódů ve vaší tabulce (invoice ).

Lze to provést pomocí prostého SQL, ale není to triviální úloha . Kroky mohou být:

  1. Zadejte rozsahy dat jako filtry.

  2. Zkombinujte časová období ve invoice tabulka na kód. Může mít za následek jeden nebo více rozsahů na kód.

  3. Hledejte překrývání mezi filtry a kombinovanými fakturami

  4. Klasifikujte:plně pokryto / částečně pokryto. Může vést k jednomu plnému pokrytí, jednomu nebo dvěma částečným pokrytím nebo žádnému pokrytí. Snížit na maximální úroveň pokrytí.

  5. Zobrazte jeden řádek pro každou kombinaci (filtr, kód) s výsledným pokrytím v rozumném pořadí řazení

Rozsahy filtrů ad hoc

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;

Nebo vložte je do (dočasné) tabulky a místo toho použijte tabulku.

Kombinovat překrývající se / sousedící období podle kódu

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

Alternativní konečný SELECT (může být rychlejší nebo ne, budete muset vyzkoušet):

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;

Sloučit do jednoho dotazu

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;

Testováno a funguje mi na PostgreSQL 9.1.




  1. Jak najít nastavení ANSI_NULLS databáze v SQL Server (T-SQL)

  2. Zkouška tipy a rady pro správu Azure SQL Database (DP-300)

  3. Jak získat více sloupců z jednoho sloupce, SQL

  4. Jak synchronizovat databáze MySQL mezi dvěma vzdálenými databázemi (bez techniky replikace databáze MySQL)