PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

So sánh nhiều phạm vi ngày

Sau khi làm rõ trong bình luận.

Nhiệm vụ của bạn theo tôi hiểu:

Kiểm tra tất cả cá nhân được cung cấp phạm vi ngày (filter ) liệu chúng có được bảo hiểm bởi kết hợp phạm vi ngày của các bộ mã trong bảng của bạn (invoice ).

Nó có thể được thực hiện với SQL thuần túy, nhưng nó không phải là một nhiệm vụ tầm thường . Các bước có thể là:

  1. Cung cấp phạm vi ngày dưới dạng bộ lọc.

  2. Kết hợp phạm vi ngày trong invoice bảng trên mỗi mã. Có thể dẫn đến một hoặc nhiều phạm vi cho mỗi mã.

  3. Tìm sự trùng lặp giữa các bộ lọc và các hóa đơn được kết hợp

  4. Phân loại:được bảo hiểm toàn bộ / được bảo hiểm một phần. Có thể dẫn đến một phạm vi bảo hiểm toàn bộ, một hoặc hai bảo hiểm một phần hoặc không bảo hiểm.

  5. Hiển thị một hàng cho mọi kết hợp (bộ lọc, mã) với phạm vi kết quả, theo thứ tự sắp xếp hợp lý

Phạm vi bộ lọc đặc biệt

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;

Hoặc đặt chúng vào một bảng (tạm thời) và sử dụng bảng thay thế.

Kết hợp các phạm vi ngày trùng lặp / liền kề trên mỗi mã

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

CHỌN cuối cùng thay thế (có thể nhanh hơn hoặc không, bạn sẽ phải kiểm tra):

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;

Kết hợp thành một truy vấn

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;

Đã thử nghiệm và hoạt động cho tôi trên 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. ProgrammingError:lỗi cú pháp tại hoặc gần khi thực hiện truy vấn trong python bằng psycopg2

  2. Làm cách nào để sử dụng kiểu nhập văn bản dưới dạng (các) tên cột trong hàm Postgres?

  3. Tại sao quan hệ setval () Fail Với ... không tồn tại?

  4. quá trình di chuyển ruby ​​đã quay trở lại nhưng gặp lỗi khi chạy lại quá trình di chuyển

  5. Lưu trữ PostgreSQL ARRAY của các giá trị ENUM