टिप्पणी में स्पष्टीकरण के बाद।
आपका कार्य जैसा कि मैं इसे समझता हूं:
सभी आपूर्ति किए गए व्यक्तिगत . की जांच करें दिनांक सीमाएँ (filter
) क्या वे संयुक्त . द्वारा कवर किए गए हैं आपकी तालिका में कोड के सेट की दिनांक सीमाएँ (invoice
)।
यह सादे SQL के साथ किया जा सकता है, लेकिन यह एक तुच्छ कार्य नहीं है . ये कदम हो सकते हैं:
-
आपूर्ति तिथि फ़िल्टर के रूप में होती है।
-
दिनांक सीमाओं को
invoice
में संयोजित करें प्रति कोड तालिका। प्रति कोड एक या अधिक श्रेणियों में परिणाम हो सकता है। -
फ़िल्टर और संयुक्त इनवॉइस के बीच ओवरलैप देखें
-
वर्गीकृत करें:पूरी तरह से कवर / आंशिक रूप से कवर किया गया। इसके परिणामस्वरूप एक पूर्ण कवरेज, एक या दो आंशिक कवरेज या कोई कवरेज नहीं हो सकता है। कवरेज के अधिकतम स्तर तक कम करें।
-
परिणामी कवरेज के साथ (फ़िल्टर, कोड) के प्रत्येक संयोजन के लिए एक पंक्ति को एक समझदार क्रम में प्रदर्शित करें
तदर्थ फ़िल्टर श्रेणियां
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 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;
एक क्वेरी से संयोजित करें
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 पर काम करता है।