【问题标题】:Find the last weekday for a given month in PostgreSQL在 PostgreSQL 中查找给定月份的最后一个工作日
【发布时间】:2013-04-03 18:29:49
【问题描述】:

在 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

谢谢

【问题讨论】:

  • 不同类型的假期呢?您也需要对它们进行特殊处理吗?在这种情况下,可能会在合适的时间段内用每个月的最后一天填充一个小表格。
  • 这是一种复杂的说法,“返回给定月份的最后一个工作日?”
  • 谢谢普伦德拉。现在你让我想我需要重新提出我的问题。我可以看到假期将如何成为一个考虑因素。在我的数据世界中,唯一导致月末日期缺失的事件是月末在星期六或星期日。
  • 是的,我认为 Mike Sherrill 'Catcall' 是正确的,我需要重新表述这个问题。

标签: sql postgresql greenplum


【解决方案1】:

A calendar table 确实简化了此类查询的 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'

【讨论】:

    【解决方案2】:
    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
    

    【讨论】:

      【解决方案3】:

      一种解决方案是使用 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 
      

      【讨论】:

        【解决方案4】:

        您想要做的是从该月的最后一天(您拥有的)中删除 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 计算。

        【讨论】:

          【解决方案5】:

          您实际上可以在没有 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;
          

          【讨论】:

          • 你不需要CASE这个表达式,直接写greatest(0, extract(isodow from last_day_of_month) - 5 ) * INTERVAL '1' DAY
          • 我已经放弃亲自询问了;开车投票似乎是该网站的危险。
          【解决方案6】:
          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;
          

          【讨论】:

            猜你喜欢
            • 2016-09-23
            • 1970-01-01
            • 1970-01-01
            • 2016-06-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多