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;
Biến thể này không cần chọn phụ, GREATEST
hoặc GROUP BY
và chỉ tạo các hàng bắt buộc. Đơn giản hơn, nhanh hơn. Nó rẻ hơn cho UNION
một hàng.
-
Thêm 6 ngày vào ngày đầu tiên của tháng trước
date_trunc('week', ...)
để tính toán Thứ Hai đầu tiên của tháng . -
Cộng 1 tháng và trừ đi 1 ngày trước
date_trunc('week', ...)
để có được Thứ Hai cuối cùng của tháng .
Điều này có thể được nhồi vào mộtinterval
một cách thuận tiện biểu thức:'1 month - 1 day'
-
UNION
( khôngUNION ALL
) ngày đầu tiên của tháng để thêm nó trừ khi nó đã được đưa vào là Thứ Hai. -
Lưu ý rằng
date
+interval
kết quả trongtimestamp
, đó là tối ưu ở đây. Giải thích chi tiết:
Tự động hóa
Bạn có thể cung cấp ngày bắt đầu chuỗi ngày trong 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;
Hoặc gói nó thành một hàm SQL đơn giản để thuận tiện với các cuộc gọi lặp lại:
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;
Gọi:
SELECT * FROM f_week_starts_this_month('2013-02-01');
Bạn sẽ vượt qua ngày cho ngày đầu tiên của tháng, nhưng nó hoạt động cho bất kỳ ngày. Bạn vào ngày đầu tiên và tất cả các ngày Thứ Hai của tháng tiếp theo.