SELECT generate_series(date_trunc('week', date '2013-02-01' + interval '6 days')
, date_trunc('week', date '2013-02-01' + interval '1 month - 1 day')
, interval '1 week')::date AS day
UNION SELECT date '2013-02-01'
ORDER BY 1;
Ten wariant nie wymaga podselekcji, GREATEST
lub GROUP BY
i generuje tylko wymagane wiersze. Prościej, szybciej. Taniej jest UNION
jeden rząd.
-
Dodaj 6 dni do pierwszego dnia miesiąca przed
date_trunc('week', ...)
aby obliczyć pierwszy poniedziałek miesiąca . -
Dodaj 1 miesiąc i odejmij 1 dzień przed
date_trunc('week', ...)
aby uzyskać ostatni poniedziałek miesiąca .
Można to wygodnie umieścić w jednyminterval
wyrażenie:'1 month - 1 day'
-
UNION
(nieUNION ALL
) pierwszego dnia miesiąca, aby go dodać, chyba że jest już uwzględniony jako poniedziałek. -
Zwróć uwagę, że
date
+interval
wyniki wtimestamp
, który jest tutaj optymalny. Szczegółowe wyjaśnienie:
Automatyzacja
Możesz podać początek serii dat w CTE:
WITH t(d) AS (SELECT date '2013-02-01') -- enter 1st of month once
SELECT generate_series(date_trunc('week', d + interval '6 days')
, date_trunc('week', d + interval '1 month - 1 day')
, interval '1 week')::date AS day
FROM t
UNION SELECT d FROM t
ORDER BY 1;
Lub zapakuj go w prostą funkcję SQL dla wygody z powtarzającymi się wywołaniami:
CREATE OR REPLACE FUNCTION f_week_starts_this_month(date)
RETURNS SETOF date AS
$func$
SELECT generate_series(date_trunc('week', $1 + interval '6 days')
, date_trunc('week', $1 + interval '1 month - 1 day')
, interval '1 week')::date AS day
UNION
SELECT $1
ORDER BY 1
$func$ LANGUAGE sql IMMUTABLE;
Zadzwoń:
SELECT * FROM f_week_starts_this_month('2013-02-01');
Datę można przekazać na pierwszy dzień miesiąca, ale działa to w przypadku każdego data. Ty pierwszy dzień i wszystkie poniedziałki w następnym miesiącu.