Мне нравится использовать таблицу календаря для запросов, подобных этому.
Чтобы выбрать третий понедельник каждого месяца в 2015 году, я могу запросить такую таблицу календаря.
select cal_date
from calendar
where year_of_date = 2015
and day_of_week = 'Mon'
and day_of_week_ordinal = 3
order by cal_date;
cal_date
--
2015-01-19
2015-02-16
2015-03-16
2015-04-20
2015-05-18
2015-06-15
2015-07-20
2015-08-17
2015-09-21
2015-10-19
2015-11-16
2015-12-21
код для создания таблицы календаря. (Это как pgAdminIII представляет его через CREATE SCRIPT меню выбора.)
CREATE TABLE calendar
(
cal_date date NOT NULL,
year_of_date integer NOT NULL,
month_of_year integer NOT NULL,
day_of_month integer NOT NULL,
day_of_week character(3) NOT NULL,
day_of_week_ordinal integer NOT NULL,
iso_year integer NOT NULL,
iso_week integer NOT NULL,
cal_quarter integer,
CONSTRAINT calendar_pkey PRIMARY KEY (cal_date),
CONSTRAINT cal_quarter_check CHECK (cal_quarter =
CASE
WHEN date_part('month'::text, cal_date) >= 1::double precision AND date_part('month'::text, cal_date) <= 3::double precision THEN 1
WHEN date_part('month'::text, cal_date) >= 4::double precision AND date_part('month'::text, cal_date) <= 6::double precision THEN 2
WHEN date_part('month'::text, cal_date) >= 7::double precision AND date_part('month'::text, cal_date) <= 9::double precision THEN 3
WHEN date_part('month'::text, cal_date) >= 10::double precision AND date_part('month'::text, cal_date) <= 12::double precision THEN 4
ELSE NULL::integer
END),
CONSTRAINT cal_quarter_range CHECK (cal_quarter >= 1 AND cal_quarter <= 4),
CONSTRAINT calendar_check CHECK (year_of_date::double precision = date_part('year'::text, cal_date)),
CONSTRAINT calendar_check1 CHECK (month_of_year::double precision = date_part('month'::text, cal_date)),
CONSTRAINT calendar_check2 CHECK (day_of_month::double precision = date_part('day'::text, cal_date)),
CONSTRAINT calendar_check3 CHECK (day_of_week::text =
CASE
WHEN date_part('dow'::text, cal_date) = 0::double precision THEN 'Sun'::text
WHEN date_part('dow'::text, cal_date) = 1::double precision THEN 'Mon'::text
WHEN date_part('dow'::text, cal_date) = 2::double precision THEN 'Tue'::text
WHEN date_part('dow'::text, cal_date) = 3::double precision THEN 'Wed'::text
WHEN date_part('dow'::text, cal_date) = 4::double precision THEN 'Thu'::text
WHEN date_part('dow'::text, cal_date) = 5::double precision THEN 'Fri'::text
WHEN date_part('dow'::text, cal_date) = 6::double precision THEN 'Sat'::text
ELSE NULL::text
END),
CONSTRAINT calendar_check4 CHECK (day_of_week_ordinal =
CASE
WHEN day_of_month >= 1 AND day_of_month <= 7 THEN 1
WHEN day_of_month >= 8 AND day_of_month <= 14 THEN 2
WHEN day_of_month >= 15 AND day_of_month <= 21 THEN 3
WHEN day_of_month >= 22 AND day_of_month <= 28 THEN 4
ELSE 5
END),
CONSTRAINT calendar_check5 CHECK (iso_year::double precision = date_part('isoyear'::text, cal_date)),
CONSTRAINT calendar_check6 CHECK (iso_week::double precision = date_part('week'::text, cal_date))
)
WITH (
OIDS=FALSE
);
Также нужно
- предоставлять и отзывать statments - очень немногие люди должны иметь возможность изменить содержание этого вида таблицы и
- подходящие инструкции CREATE INDEX.
возможно дубликат [SQL N-й день N-ой недели месяца] (http://stackoverflow.com/questions/7134137/sql-nth-day-of -nth недель из-а-месяц) –