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;
Този вариант не се нуждае от подизбор, GREATEST
или GROUP BY
и генерира само необходимите редове. По-лесно, по-бързо. По-евтино е да UNION
един ред.
-
Добавете 6 дни към първия ден на месеца преди
date_trunc('week', ...)
за изчисляване на първия понеделник от месеца . -
Добавете 1 месец и извадете 1 ден преди
date_trunc('week', ...)
за да получите последния понеделник на месеца .
Това може удобно да се постави в единinterval
израз:'1 month - 1 day'
-
UNION
(неUNION ALL
) първия ден от месеца, за да го добавите, освен ако вече не е включен като понеделник. -
Обърнете внимание на тази
date
+interval
води доtimestamp
, което е оптималното тук. Подробно обяснение:
Автоматизация
Можете да предоставите началото на поредицата от дати в 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;
Или го обвийте в проста SQL функция за удобство при повтарящи се извиквания:
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;
Обаждане:
SELECT * FROM f_week_starts_this_month('2013-02-01');
Бихте преминали датата за първия ден от месеца, но тя работи за всеки дата. Вие първия ден и всички понеделници за следващия месец.