如何在postgresql中找到当前月份的第一个和第三个星期日/星期一



有人能帮我在postgresql中找到一个月中的特定星期吗。。。如第1周和第3周的周日/周一或第2周和第4周的周三

首先,与最初的预期相反,处理日期是复杂的,有时甚至非常复杂。周数和周天数的组合属于后一类
问题源于两个ISO定义:

  • 所有星期一开始,为期7天
  • 一年中的第一周是包含1月4日的一周

这注定任何努力(至少任何合理的简单onc(都会失败。虽然这是一项令人钦佩的努力,但我将使用@Abelisto的建议作为示例。请参见Fiddle。我已经改变了这一点,刚好可以使用多个参数,而在大多数月份,这是正确的,但看看2019年1月30日至31日和2021年1月。第一个问题是,虽然ISO周完全一致,但日历却不一致。这导致给定月份的第一周与上个月的最后一周相同,反之亦然。虽然这通常可以单独解决,但当与另一个结合时就不是这样了。由于每一个都有7天的时间,而一年中的第一周包含1月4日,这就产生了更大的问题。12月的最后几天可能在明年的第一周。此外,1月的头几天可能在前一年的第52(或53(周(见fiddle中的第二个查询(。有解决方案吗?我确信外面有什么地方。我就是没有。至少有Extract函数
那么这个具体问题怎么样:基本上可以归结为获取上个月的最后一天,然后根据需要找到下一个DOW(周日或周一(。现在,从Oracle的后台,我只使用NEXT_DAY函数,它可以为我做到这一点。不幸的是,Postgres没有提供有用的函数。但你可以自己滚。下面我提供了几个我在Postgres中编写的函数。它由2个Postgres SQL函数组成:
-utl_dates_first_dow_of_month((。它采用两个参数,目标日期(DOW(作为日期名称的前3个字符(不区分大小写(和所需月份的日期。它返回DATE,这是请求的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);
$$;

现在,在手头的问题上,这已经解决了。正如Abelisto和其他人所指出的那样,这个请求是模棱两可的。没有第一个或第三个星期日/星期一这回事。你想要一个月的第一个星期日和第三个星期日以及第一个星期一和第三次星期一吗?你想要吗你想分别在本月的第一个星期日和第三个星期日以及下一个星期一吗。你想要一个月的第一周和第三周的星期日和星期一吗(如果是,星期一总是较早的日期,请参见上面的定义1(?请尽量对你的问题更加具体。并包括测试数据-作为文本无图像-以及该数据的预期结果。然而,这些解决方案只是彼此之间的微小修改。(没有第三种可能性的解决方案。(

对于第一个和第三个星期日以及第一个和第一个星期一:

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; 

每月的第一个和第三个星期日以及以下星期一:

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;
select * from 
(
select dow, i, row_number() over(partition by dow order by i) as rnk from
(
select 
extract(dow from i::date) as dow, 
i::date 
from generate_series('2022-10-01'::date,'2022-10-31'::date,interval '1 Day') i
) tmp where dow = 1
)tmp_out where rnk = 3;

最新更新