2015-03-17 2 views
0

Я не уверен, с чего начать решение этой проблемы. Мне нужно обновить запись, которая будет только каждый третий понедельник месяца. В Postgres я могу запросить каждый второй или третий понедельник или немного более абстрактно каждый n-й день n-й недели?Query Only Specific Days of Month

Я ищу элегантный ответ с помощью Postgresql. Прямо сейчас у меня есть что-то грубое:

select d from generate_series(date_trunc('week',timestamp '2015-02-01' + interval '13 days'), timestamp '2015-02-01' + interval '1 month -1 day', interval '14 days') d; 
+0

возможно дубликат [SQL N-й день N-ой недели месяца] (http://stackoverflow.com/questions/7134137/sql-nth-day-of -nth недель из-а-месяц) –

ответ

1

Мне нравится использовать таблицу календаря для запросов, подобных этому.

Чтобы выбрать третий понедельник каждого месяца в 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.
0

Может попробовать это:

SELECT * 
    , EXTRACT(DAY FROM gen)::int as dom -- DayOfMonth 
    , CEIL(EXTRACT(DAY FROM gen)/7)::int as mow -- MonthOfWeek 
from (
    select generate_series(date_trunc('year', now()), date_trunc('year', now() + interval '1 year'), interval '1 day')::date as gen 
) as src 
WHERE extract ('dow' from gen) = 1 
AND CEIL(EXTRACT(DAY FROM gen)/7)::int in (2,3)