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 não precisa de uma subseleção,
GREATEST
ou GROUP BY
e gera apenas as linhas necessárias. Mais simples, mais rápido. É mais barato usar UNION
uma linha. -
Adicione 6 dias ao primeiro dia do mês antes dedate_trunc('week', ...)
para calcular a primeira segunda-feira do mês .
-
Adicione 1 mês e subtraia 1 dia antes dedate_trunc('week', ...)
para obter a última segunda-feira do mês .
Isso pode ser convenientemente colocado em um únicointerval
expressão:'1 month - 1 day'
-
UNION
(nãoUNION ALL
) no primeiro dia do mês para adicioná-lo, a menos que já esteja incluído como segunda-feira.
-
Observe quedate
+interval
resulta emtimestamp
, que é o ideal aqui. Explicação detalhada:
Automação
Você pode fornecer o início da série de datas em um 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;
Ou envolva-o em uma função SQL simples por conveniência com chamadas 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;
Ligar:
SELECT * FROM f_week_starts_this_month('2013-02-01');
Você passaria a data para o primeiro dia do mês, mas funciona para qualquer encontro. Você no primeiro dia e todas as segundas-feiras do mês seguinte.