Как найти 1-е и 3-е воскресенье / понедельник текущего месяца в postgresql - PullRequest
1 голос
/ 21 марта 2020

Может ли кто-нибудь помочь мне найти конкретные c дни недели месяца в postgresql ... как 1-я и 3-я недели воскресенье / понедельник или 2-я и 4-я недели среда

1 Ответ

1 голос
/ 23 марта 2020

Во-первых, вопреки первоначальным ожиданиям, работа с датами сложна, иногда чрезвычайно. Комбинация номеров недели и дней недели относятся к последней категории. Проблема связана с двумя определениями ISO:

  • Все недели начинаются с понедельника и длятся 7 дней.
  • Первая неделя года - это неделя, содержащая 4 января.

Это обрекает любые усилия (по крайней мере, на любое простое на c) на провал. В то время как замечательное усилие я буду использовать предложение @Abelisto в качестве образца. См. Скрипку . Я изменил это достаточно, чтобы использовать несколько параметров, хотя в большинстве месяцев это правильно, но посмотрите на 30,31-январь-2019 и январь-2021. Проблема с первым существом, когда неделя ИСО совершенно соответствует календарю, нет. Это приводит к тому, что первая неделя данного месяца совпадает с последней неделей предыдущего месяца, и наоборот. Хотя обычно это можно обойти самостоятельно, но не в сочетании с другими. В результате, каждый из которых длится 7 дней, а первая неделя года, содержащая 4 января, порождает большую проблему. Последние несколько дней De c возможно на 1-й неделе следующего года. Также первые дни января могут быть на 52 (или 53) неделе предыдущего года (см. 2-й запрос в скрипке). Есть ли решение? Я уверен, что где-то там есть. У меня просто этого нет. По крайней мере, с функцией извлечения. Итак, как насчет этой конкретной проблемы: в общем, все сводится к получению последнего дня предыдущего месяца, а затем к поиску следующего DOW (воскресенье или понедельник) по мере необходимости. Теперь, исходя из Oracle фона, я бы просто использовал функцию NEXT_DAY, которая бы сделала это для меня. К сожалению, Postgres не предоставляет эту полезную функцию. Но вы можете свернуть свои собственные. Ниже я приведу пару функций, которые я написал для выполнения этой функции в Postgres. Он состоит из 2 Postgres SQL функций: - utl_dates_first_dow_of_month (). Он принимает 2 параметра: целевой день недели (DOW) в качестве первых 3 символов названия дня (без учета регистра) и дату в желаемом месяце. Он возвращает ДАТУ, которая является первым вхождением запрошенного DOW.
- utl_dates_next_dow (). Он принимает те же 2 параметра и возвращает следующую календарную дату указанной DOW от указанной даты. Если указанная дата попадает в запрошенный DOW, процедура НЕ возвращает указанную дату. Функция фактически используется первой. К счастью, подпрограммы короче, чем описание.

create or replace function utl_dates_next_dow(dow_in text, date_in date)
 returns   date
 language  sql
 immutable strict  
as $$
-- Given a DOW and a date return the calendar date for the next occurrence of DOW
with dy as (select string_to_array('mon,tue,wed,thu,fri,sat,sun', ',') dl)
   , dn as (select array_position(dl, (substring(to_char(date_in, 'day'),1,3))) fn  
                 , array_position(dl, lower(substring(dow_in,1,3)))             dn
              from dy 
           )
select case when dn <= fn
            then (date_in + (dn+7-fn) * interval '1 day')::date 
            else (date_in + (dn-fn)   * interval '1 day')::date
       end 
  from dn; 
$$;

create or replace function utl_dates_first_dow_of_month(dow_in text, date_in date)
 returns   date
 language  sql
 immutable strict  
as $$
-- Given a DOW and a Date return the calendar date of the first specified dow in which the specified date falls.
select utl_dates_next_dow(dow_in,  (date_trunc('month', date_in) - interval '1 day')::date);
$$;

Теперь с этим по пути к решению данной проблемы. Как Абелисто, так и другие указывают на просьбу неоднозначно. Нет такого понятия, как 1-е или 3-е воскресенье / понедельник. Вы хотите 1-е и 3-е воскресенье и 1-й и 3-й понедельник месяца? Хотите ли вы хотите 1-е и 3-е воскресенье месяца и понедельник, следующий за каждым соответственно. Хотите ли вы воскресенье и понедельник для 1-й и 3-й недели месяца (если это так, понедельник всегда будет более ранней датой, см. Определение 1 выше)? Пожалуйста, постарайтесь быть более точным с вашими вопросами. И включите данные испытаний - в виде текста без изображений - и ожидаемые результаты из этих данных. Решения, однако, являются лишь незначительными изменениями друг друга. (Нет решения для 3-й перечисленной возможности.)

Для случая 1-го и 3-го воскресенья и 1-го и 3-го понедельника:

with parms (dt) as (values ( date '2020-04-01'), (date '2020-06-01') )
   , base_dates( fsun, fmon) as 
     ( select utl_dates_first_dow_of_month('Sun',dt) 
            , utl_dates_first_dow_of_month('Mon',dt)
         from parms
     ) 
select '1st & 3rd Sunday and 1st & 3rd Monday' 
     , fsun   "1st Sunday"
     , (fsun+interval '14 days')::date "3rd Sunday"     
     , fmon   "1st Monday"
     , (fmon+interval '14 days')::date "3rd Monday" 
  from base_dates; 

Для 1-го и 3-го воскресенья месяца и понедельник следующий:

with parms (dt) as (values ( date '2020-04-01'), (date '2020-06-01') )
   , base_dates( fsun, fmon) as 
     ( select utl_dates_first_dow_of_month('Sun',dt)
            , (utl_dates_first_dow_of_month('Sun',dt)+interval '1 day')::date  
         from parms
     ) 
select '1st & 3rd Sunday and Monday Following '  
     , fsun   "1st Sunday"
     , fmon   "1st Monday"
     , (fsun+interval '14 days')::date "3rd Sunday"
     , (fmon+interval '14 days')::date "3rd Monday" 
  from base_dates;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...