3

在 PostgreSQL 中查找给定月份的最后一个工作日

用法:如果月末在星期六或星期日,则返回上一个星期五,否则使用月末

例子:

  • 2013 年 3 月 31 日是星期天,所以返回 2013 年 3 月 29 日
  • 2013 年 11 月 30 日是星期六,所以返回 2013 年 11 月 29 日

如何在 PostgreSQL SQL 中编写这个?

到目前为止,我所拥有的是(仅返回月末,但是当它们落在星期六或星期日时,月末不存在):

SELECT as_of_dt, sum(bank_shr_bal) as bank_shr_bal 
  FROM hm_101.vw_gl_bal 
 WHERE as_of_dt = (date_trunc('MONTH', as_of_dt) + INTERVAL '1 MONTH - 1 day')::date 
GROUP BY 1

谢谢

4

6 回答 6

1
with s as (
    select *, (date_trunc('MONTH', as_of_dt) + INTERVAL '1 MONTH - 1 day')::date last_day
    from
    hm_101.vw_gl_bal
)
SELECT
    as_of_dt,
    gl_acct_nbr,
    cc_nbr,
    sum(bank_shr_bal) as bank_shr_bal
FROM s
WHERE as_of_dt = (
    last_day
    -
    (extract(dow from last_day) = 5)::int
    -
    2 * (extract(dow from last_day) = 6)::int
    )
GROUP BY 1,2,3
于 2013-04-11T15:10:56.087 回答
1

日历表确实简化了此类查询的 SQL。(“weekdays”表实际上是基于日历表的视图。它的结构应该很明显。)

select max(cal_date)
from weekdays
where cal_date < '2013-05-01'

或者

select max(cal_date)
from weekdays
where cal_date between '2013-04-01' and '2013-04-30'
于 2013-04-11T15:52:45.193 回答
0
select 
case
  when extract(dow from first_day_of_month) = 0 then first_day_of_month 
  when extract(dow from first_day_of_month) = 1 then first_day_of_month - 1
  when extract(dow from first_day_of_month) = 2 then first_day_of_month - 2
  when extract(dow from first_day_of_month) = 3 then first_day_of_month - 3
  when extract(dow from first_day_of_month) = 4 then first_day_of_month - 4
  when extract(dow from first_day_of_month) = 5 then first_day_of_month - 5
  when extract(dow from first_day_of_month) = 6 then first_day_of_month - 6
  end as first_weekday_of_month,
case 
  when extract(dow from last_day_of_month)  = 6 then last_day_of_month 
  when extract(dow from last_day_of_month)  = 5 then last_day_of_month - 6 
  when extract(dow from last_day_of_month)  = 4 then last_day_of_month - 5 
  when extract(dow from last_day_of_month)  = 3 then last_day_of_month - 4 
  when extract(dow from last_day_of_month)  = 2 then last_day_of_month - 3 
  when extract(dow from last_day_of_month)  = 1 then last_day_of_month - 2 
  when extract(dow from last_day_of_month)  = 0 then last_day_of_month - 1
  end as last_weekday_of_month
from(
  SELECT   
    (date_trunc('month', current_date) -'7day'::interval)::date first_day_of_month,
    (date_trunc('month', current_date) -'1day'::interval)::date as last_day_of_month
)subquery;
于 2013-12-11T12:19:54.203 回答
0

一种解决方案是使用 CTE,在数据中逐月查找最后一天以及每个月的实际最后一天

WITH s1
as
(
SELECT 
 date_part('YEAR', as_of_dt) AOD_Year
,date_part('MONTH', as_of_dt) AOD_Month
,(date_trunc('MONTH', as_of_dt) + INTERVAL '1 MONTH - 1 day')::date AOD_MonthEnd
,max(as_of_dt) AOD_LastFound
  FROM hm_101.vw_gl_bal
where (date_trunc('MONTH', as_of_dt) + INTERVAL '1 MONTH - 1 day')::date = '2013-03-31'
 group by 1, 2, 3
)
SELECT 
 s1.AOD_MonthEnd
,s1.AOD_LastFound
,sum(v.bank_shr_bal) as bank_shr_bal 
  FROM hm_101.vw_gl_bal v
 INNER JOIN s1
    on v.as_of_dt = s1.AOD_LastFound
 WHERE v.as_of_dt = '2013-03-29'  
 GROUP BY 1, 2 
于 2013-04-11T14:48:53.800 回答
0

您想要做的是从该月的最后一天(您拥有)中删除 0 到 2 天。

通过提取星期几 (DOW) 并检查它是 0(星期日)还是 6(星期六),我们知道要删除多少天。

你可以这样做:

... - INTERVAL '1 day' * CASE date_part('DOW', last_day_of_month)
                             WHEN 0 THEN 2 -- Sunday, remove 2 days.
                             WHEN 6 THEN 1 -- Saturday, remove 1 day.
                             ELSE 0 -- Don't remove any days.
                         END

为了便于阅读,我没有在其中包含完整的 last_day_of_month 计算。

于 2013-04-11T15:06:35.143 回答
0

您实际上可以在没有 CTE 或存储过程的情况下执行此操作。

select 
case 
  when extract(dow from last_day_of_month) = 0 
    then last_day_of_month - 2
  when extract(dow from last_day_of_month) = 6 
    then last_day_of_month - 1
  else 
    last_day_of_month 
end as last_weekday_of_month
from(
  SELECT (date_trunc('MONTH', as_of_dt) 
    + INTERVAL '1 MONTH - 1 day')::date as last_day_of_month
  from hm_101.vw_gl_bal 
)subquery;
于 2013-04-11T15:07:37.193 回答