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;
Esta variante no necesita una subselección, GREATEST
o GROUP BY
y solo genera las filas requeridas. Más simple, más rápido. Es más barato UNION
una fila.
-
Agregue 6 días al primer día del mes antes de
date_trunc('week', ...)
para calcular el primer lunes del mes . -
Suma 1 mes y resta 1 día antes de
date_trunc('week', ...)
para obtener el último lunes del mes .
Esto se puede incluir convenientemente en un solointerval
expresión:'1 month - 1 day'
-
UNION
(noUNION ALL
) el primer día del mes para agregarlo a menos que ya esté incluido como lunes. -
Tenga en cuenta que
date
+interval
da como resultadotimestamp
, que es lo óptimo aquí. Explicación detallada:
Automatización
Puede proporcionar el inicio de la serie de fechas en 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;
O envuélvalo en una función SQL simple para mayor comodidad con llamadas repetidas:
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;
Llamar:
SELECT * FROM f_week_starts_this_month('2013-02-01');
Pasaría la fecha para el primer día del mes, pero funciona para cualquier fecha. Tú el primer día y todos los lunes del mes siguiente.