PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Générer des séries d'intervalles hebdomadaires pour un mois donné

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 seul interval expression :'1 month - 1 day'

  • UNION (pas UNION 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 dans timestamp , 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.