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;
Varian ini tidak memerlukan subselect, GREATEST
atau GROUP BY
dan hanya menghasilkan baris yang diperlukan. Lebih sederhana, lebih cepat. Lebih murah untuk UNION
satu baris.
-
Tambahkan 6 hari ke hari pertama setiap bulan sebelum
date_trunc('week', ...)
untuk menghitung Senin pertama setiap bulan . -
Tambahkan 1 bulan dan kurangi 1 hari sebelum
date_trunc('week', ...)
untuk mendapatkan Senin terakhir setiap bulan .
Ini dapat dengan mudah dimasukkan ke dalam satuinterval
ekspresi:'1 month - 1 day'
-
UNION
(tidakUNION ALL
) hari pertama setiap bulan untuk menambahkannya kecuali sudah dimasukkan sebagai Senin. -
Perhatikan bahwa
date
+interval
menghasilkantimestamp
, yang merupakan optimal di sini. Penjelasan detail:
Otomasi
Anda dapat memberikan awal rangkaian tanggal dalam 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;
Atau bungkus menjadi fungsi SQL sederhana untuk kenyamanan dengan panggilan berulang:
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;
Telepon:
SELECT * FROM f_week_starts_this_month('2013-02-01');
Anda akan melewati tanggal untuk hari pertama bulan itu, tetapi ini berfungsi untuk apa saja tanggal. Anda hari pertama dan semua hari Senin untuk bulan berikutnya.