PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Bandingkan beberapa rentang tanggal

Setelah klarifikasi dalam komentar.

Tugas Anda seperti yang saya pahami:

Periksa semua individu yang disediakan rentang tanggal (filter ) apakah mereka dicakup oleh gabungan rentang tanggal kumpulan kode di tabel Anda (invoice ).

Hal ini dapat dilakukan dengan SQL biasa, tetapi bukan tugas sepele . Langkah-langkahnya bisa:

  1. Rentang tanggal suplai sebagai filter.

  2. Gabungkan rentang tanggal dalam invoice tabel per kode. Dapat menghasilkan satu atau beberapa rentang per kode.

  3. Cari tumpang tindih antara filter dan faktur gabungan

  4. Klasifikasikan:tercakup sepenuhnya / tercakup sebagian.Dapat menghasilkan satu pertanggungan penuh, satu atau dua pertanggungan sebagian atau tanpa pertanggungan.Kurangi hingga tingkat pertanggungan maksimum.

  5. Tampilkan satu baris untuk setiap kombinasi (filter, kode) dengan cakupan yang dihasilkan, dalam urutan yang masuk akal

Rentang filter 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;

Atau letakkan di tabel (sementara) dan gunakan tabel sebagai gantinya.

Gabungkan rentang tanggal yang tumpang tindih / berdekatan per kode

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

PILIH akhir alternatif (mungkin lebih cepat atau tidak, Anda harus menguji):

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;

Gabungkan ke satu kueri

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;

Diuji dan berfungsi untuk saya di PostgreSQL 9.1.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Hapus baris duplikat dari tabel tanpa kunci unik

  2. Lihat alias nama kolom di klausa WHERE

  3. Bagaimana cara memberi label grup di postgresql ketika kepemilikan grup bergantung pada baris sebelumnya?

  4. Pemulihan cadangan PostgreSQL dan TimescaleDB menggunakan ClusterControl CLI

  5. Bagaimana cara menentukan apakah NULL terkandung dalam array di Postgres?