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;
Questa variante non necessita di una sottoselezione, GREATEST
o GROUP BY
e genera solo le righe richieste. Più semplice, più veloce. È più economico UNION
una riga.
-
Aggiungi 6 giorni al primo giorno del mese prima di
date_trunc('week', ...)
per calcolare il primo lunedì del mese . -
Aggiungi 1 mese e sottrai 1 giorno prima di
date_trunc('week', ...)
per ricevere l'ultimo lunedì del mese .
Questo può essere comodamente inserito in un unicointerval
espressione:'1 month - 1 day'
-
UNION
(nonUNION ALL
) il primo giorno del mese per aggiungerlo a meno che non sia già incluso come lunedì. -
Nota che
date
+interval
risulta intimestamp
, che è l'ottimo qui. Spiegazione dettagliata:
Automazione
Puoi fornire l'inizio della serie di date in un 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;
Oppure avvolgilo in una semplice funzione SQL per comodità con chiamate ripetute:
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;
Chiama:
SELECT * FROM f_week_starts_this_month('2013-02-01');
Passeresti la data del primo giorno del mese, ma funziona per qualsiasi Data. Tu il primo giorno e tutti i lunedì del mese successivo.