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;
Denne variant behøver ikke et undervalg, GREATEST
eller GROUP BY
og genererer kun de nødvendige rækker. Enklere, hurtigere. Det er billigere at UNION
en række.
-
Tilføj 6 dage til den første dag i måneden før
date_trunc('week', ...)
for at beregne den første mandag i måneden . -
Tilføj 1 måned og træk 1 dag før
date_trunc('week', ...)
for at få den sidste mandag i måneden .
Dette kan bekvemt fyldes i et enkeltinterval
udtryk:'1 month - 1 day'
-
UNION
(ikkeUNION ALL
) den første dag i måneden for at tilføje den, medmindre den allerede er inkluderet som mandag. -
Bemærk at
date
+interval
resulterer itimestamp
, hvilket er det optimale her. Detaljeret forklaring:
Automatisering
Du kan angive starten på datoserien i en 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;
Eller pak den ind i en simpel SQL-funktion for nemheds skyld med gentagne opkald:
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;
Ring til:
SELECT * FROM f_week_starts_this_month('2013-02-01');
Du ville passere datoen for den første dag i måneden, men den virker for alle dato. Du den første dag og alle mandage i den følgende måned.