sql >> Base de Datos >  >> RDS >> PostgreSQL

Generar series de intervalos de semana para un mes dado

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 solo interval expresión:'1 month - 1 day'

  • UNION (no UNION 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 resultado timestamp , 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.