有什么办法在PostgreSQL中将假期与工作日分开?

时间:2019-01-19 11:17:21

标签: sql postgresql

我住在伊朗,在伊朗的假期与日历不同。我需要从工作日的周末休假。 我的日历上有伊朗假期。 我的桌子是这样的:

start_date           finish_date         datediff(day)
---------------------------------------------------
03/03/2018           03/09/2018          6
03/10/2018           03/21/2018          11

我知道这些天包括伊朗的假期:

03/05/2018
03/11/2018
03/19/2018

所以我需要从任何时间间隔减少伊朗的假期。例如,时间03/05/2018在第一个间隔中,并且应该从该间隔中减少。 关键是我无法加入假期表和时间间隔表,因为它们位于两个不同的数据库上。

最终表是这样的:

start_date           finish_date         datediff(day)   Difference_of_time_ 
                                                         except_the_holidays
---------------------------------------------------------------------------
03/03/2018           03/09/2018          6                       5
03/10/2018           03/21/2018          11                      9

1 个答案:

答案 0 :(得分:1)

我在最近的两家公司中都处理过这个确切的问题。在每种情况下,一种效果很好的解决方案是维护一个包含所有工作日的工作日日历:工作日,周末,节假日并对每个工作日进行分类。它还具有运行索引,以指示是否已经过工作日。这是一个示例:

cal_date   is_workday  day_type     workday_index   workday_index_back
  7/1/2018 0           WE                    4635                 4635
  7/2/2018 1           WD                    4636                 4635
  7/3/2018 1           WD                    4637                 4636
  7/4/2018 0           HD                    4637                 4637
  7/5/2018 1           WD                    4638                 4637
  7/6/2018 1           WD                    4639                 4638
  7/7/2018 0           WE                    4639                 4639
  7/8/2018 0           WE                    4639                 4639
  7/9/2018 1           WD                    4640                 4639
 7/10/2018 1           WD                    4641                 4640
 7/11/2018 1           WD                    4642                 4641
 7/12/2018 1           WD                    4643                 4642
 7/13/2018 1           WD                    4644                 4643
 7/14/2018 0           WE                    4644                 4644
 7/15/2018 0           WE                    4644                 4644

(7月4日是美国的假期)。

workday_index字段在每个工作日递增,而不在非工作日递增。您可以想象,一旦定义了假期日历,该表就很容易构建。

这些数字本身并不意味着任何东西,它们只是一种用于计算整个日历中工作日数的机制。

从这里开始,计算日期之间的差就很容易了:

select
  t.start_date, t.finish_date,
  t.finish_date - t.start_date as calendar_days,
  wd2.workday_index - wd1.workday_index as work_days
from
  table t
  join work_days wd1 on t.start_date = wd1.cal_date
  join work_days wd2 on t.finish_date = wd2.cal_date

您还可以执行类似计算工作天数的操作。例如,如果您有客户需要的日期和交货时间(生产天数),则可以如下计算最新的开始日期:

select
  c.need_date, c.lead_time_days, 
  wd2.cal_date as earliest_possible_start_date
from
  customer_data c
  join util.work_days wd1 on c.need_date = wd1.cal_date
  join util.work_days wd2 on wd1.workday_index - c.lead_time_days = wd2.workday_index

作为一项额外的奖励,如果您要应用前滚规则和后滚规则,则表的工作方式也有所不同-这就是为什么有两个工作日索引-向前和向后。这是适用的,因为您处理非工作日的方式可能与上下文有关。

例如,如果客户要在星期六之前购买产品-那么他的需求日期实际上是星期五(回滚)。但是,如果您承诺在周六从供应商处交货,则该日期需要前移-直到星期一才真正收到。