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;
Deze variant heeft geen subselectie nodig, GREATEST
of GROUP BY
en genereert alleen de vereiste rijen. Eenvoudiger, sneller. Het is goedkoper om UNION
één rij.
-
Voeg 6 dagen toe aan de eerste dag van de maand voor
date_trunc('week', ...)
om de eerste maandag van de maand . te berekenen . -
Voeg 1 maand toe en trek 1 dag af voor
date_trunc('week', ...)
om de laatste maandag van de maand . te krijgen .
Dit kan gemakkelijk in een enkelinterval
worden gestopt uitdrukking:'1 month - 1 day'
-
UNION
(nietUNION ALL
) de eerste dag van de maand om het toe te voegen, tenzij het al als maandag is opgenomen. -
Merk op dat
date
+interval
resulteert intimestamp
, wat hier het optimum is. Gedetailleerde uitleg:
Automatisering
U kunt het begin van de datumreeks in een CTE opgeven:
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;
Of wikkel het voor het gemak in een eenvoudige SQL-functie met herhaalde oproepen:
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;
Bel:
SELECT * FROM f_week_starts_this_month('2013-02-01');
Je zou de datum doorgeven voor de eerste dag van de maand, maar het werkt voor elke datum. Jij de eerste dag en alle maandagen voor de volgende maand.