PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Genera serie di intervalli settimanali per un determinato mese

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 unico interval espressione:'1 month - 1 day'

  • UNION (non UNION ALL ) il primo giorno del mese per aggiungerlo a meno che non sia già incluso come lunedì.

  • Nota che date + interval risulta in timestamp , 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.