इसे CTE से हल किया जा सकता है:
WITH business_days_back AS (
WITH RECURSIVE bd(back_day, go_back) AS (
-- Go back to the previous Monday, allowing for current_date in the weekend
SELECT CASE extract(dow from current_date)
WHEN 0 THEN current_date - 6
WHEN 6 THEN current_date - 5
ELSE current_date - extract(dow from current_date)::int + 1
END,
CASE extract(dow from current_date)
WHEN 0 THEN 7
WHEN 6 THEN 7
ELSE 12 - extract(dow from current_date)::int + 1
END
UNION
-- Go back by the week until go_back = 0
SELECT CASE
WHEN go_back >= 5 THEN back_day - 7
WHEN go_back > 0 THEN back_day - 2 - go_back
END,
CASE
WHEN go_back >= 5 THEN go_back - 5
WHEN go_back > 0 THEN 0
END
FROM bd
)
SELECT back_day FROM bd WHERE go_back = 0
)
SELECT * FROM my_table WHERE analysis_date >= (SELECT * FROM business_days_back);
कुछ स्पष्टीकरण:
- आंतरिक सीटीई पिछले सोमवार को वापस काम करके शुरू होता है, एक
current_date
के लिए क्षतिपूर्ति करता है जो सप्ताहांत के दिन पड़ता है। - पुनरावर्ती शब्द फिर पूरे सप्ताह वापस जाकर पंक्तियों को जोड़ता है (
back_day - 7
कैलेंडर तिथि औरgo_back - 5
. के लिए व्यावसायिक दिनों के लिए)go_back = 0
. तक । - बाहरी सीटीई
back_day
लौटाता है दिनांक जहांgo_back = 0
. इसलिए यह एक अदिश क्वेरी है और आप इसे फ़िल्टर एक्सप्रेशन में उप-क्वेरी के रूप में उपयोग कर सकते हैं।
आप केवल 12
. संख्याओं को बदलकर पीछे मुड़कर देखने के लिए व्यावसायिक दिनों की संख्या को बदल सकते हैं और 7
आरंभिक में SELECT
आंतरिक सीटीई में। हालांकि, ध्यान रखें कि मान ऐसा होना चाहिए कि यह पिछले सोमवार को वापस चला जाए या क्वेरी विफल हो जाएगी, उसी प्रारंभिक SELECT
के कारण आंतरिक सीटीई का।
निम्नलिखित फ़ंक्शन का उपयोग करना कहीं अधिक लचीला (और शायद तेज़*) समाधान है:
CREATE FUNCTION business_days_diff(from_date date, diff int) RETURNS date AS $$
-- This function assumes Mon-Fri business days
DECLARE
start_dow int;
calc_date date;
curr_diff int;
weekend int;
BEGIN
-- If no diff requested, return the from_date. This may be a non-business day.
IF diff = 0 THEN
RETURN from_date;
END IF;
start_dow := extract(dow from from_date)::int;
calc_date := from_date;
IF diff < 0 THEN -- working backwards
weekend := -2;
IF start_dow = 0 THEN -- Fudge initial Sunday to the previous Saturday
calc_date := calc_date - 1;
start_dow := 6;
END IF;
IF start_dow + diff >= 1 THEN -- Stay in this week
RETURN calc_date + diff;
ELSE -- Work back to Monday
calc_date := calc_date - start_dow + 1;
curr_diff := diff + start_dow - 1;
END IF;
ELSE -- Working forwards
weekend := 2;
IF start_dow = 6 THEN -- Fudge initial Saturday to the following Sunday
calc_date := calc_date + 1;
start_dow := 0;
END IF;
IF start_dow + diff <= 5 THEN -- Stay in this week
RETURN calc_date + diff;
ELSE -- Work forwards to Friday
calc_date := calc_date + 5 - start_dow;
curr_diff := diff - 5 + start_dow;
END IF;
END IF;
-- Move backwards or forwards by full weeks
calc_date := calc_date + (curr_diff / 5) * 7;
-- Process any remaining days, include weekend
IF curr_diff % 5 != 0 THEN
RETURN calc_date + curr_diff % 5 + weekend;
ELSE
RETURN calc_date;
END IF;
END; $$ LANGUAGE plpgsql STRICT IMMUTABLE;
यह फ़ंक्शन भविष्य में कितने दिनों से और कितने दिनों से गणना करने के लिए कोई भी तारीख ले सकता है (diff
का सकारात्मक मान) ) या अतीत (diff
. का ऋणात्मक मान ), वर्तमान सप्ताह के भीतर अंतर सहित। और चूंकि यह कार्य दिवस की तारीख को एक अदिश राशि के रूप में लौटाता है, इसलिए आपकी क्वेरी में उपयोग करना बहुत आसान है:
SELECT *
FROM table
WHERE analysis_date >= business_days_diff(current_date, -12);
इसके अलावा, आप अपनी टेबल से खेतों में भी जा सकते हैं और मजेदार चीजें कर सकते हैं जैसे:
SELECT t1.some_value - t2.some_value AS value_diff
FROM table t1
JOIN table t2 ON t2.analysis_date = business_days_diff(t1.analysis_date, -12);
यानी एक निश्चित संख्या में व्यावसायिक दिनों के अलगाव पर स्वयं-जुड़ना।
ध्यान दें कि यह फ़ंक्शन सोमवार-शुक्रवार व्यावसायिक दिन सप्ताह मानता है।
<उप>* यह फ़ंक्शन अदिश मानों पर केवल साधारण अंकगणित करता है। सीटीई को पुनरावृत्ति और परिणामी रिकॉर्ड सेट का समर्थन करने के लिए सभी प्रकार की संरचनाएं स्थापित करनी होंगी।