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;
Cette variante n'a pas besoin d'une sous-sélection, GREATEST
ou GROUP BY
et ne génère que les lignes requises. Plus simple, plus rapide. C'est moins cher de UNION
une ligne.
-
Ajouter 6 jours au premier jour du mois avant
date_trunc('week', ...)
pour calculer le premier lundi du mois . -
Ajouter 1 mois et soustraire 1 jour avant
date_trunc('week', ...)
pour obtenir le dernier lundi du mois .
Cela peut être commodément inséré dans un seulinterval
expression :'1 month - 1 day'
-
UNION
(pasUNION ALL
) le premier jour du mois pour l'ajouter à moins qu'il ne soit déjà inclus comme lundi. -
Notez que
date
+interval
résultats danstimestamp
, qui est l'optimum ici. Explication détaillée :
Automatisation
Vous pouvez fournir le début de la série de dates dans 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;
Ou encapsulez-le dans une simple fonction SQL pour plus de commodité avec des appels répétés :
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;
Appel :
SELECT * FROM f_week_starts_this_month('2013-02-01');
Vous passeriez la date pour le premier jour du mois, mais cela fonctionne pour tout Date. Vous le premier jour et tous les lundis du mois suivant.