内容目录

  • 一、说明
  • 二、需求说明
  • 三、过滤节假日
  • 思路一
  • 思路二
  • 四、功能实现
  • 方式1:等差求解
  • 方式2:前后相减


一、说明

先说需要实现的效果,就是判断节假日和工作日,如果是工作日,返回当日,如果是节假日或者休息,返回一下次工作的日期
06-01 工作日 06-01
06-02 双休日 06-04 *因为 下一个工作日是06-04
06-03 双休日 06-04
06-07、06-08、06-09节假日, 返回06-10, 即下一个工作日

连续登录天数之前讲解过有两种解法,可以解决连续登录问题,那么在实际生产中也是经常使用到,但是对于一些此类问题的变形,是否能够轻松解决?

二、需求说明

最近接到一个需求,也不算是需求,是一个小的功能实现。之前一直再做事件告警的需求,需要对告警事件进行反馈,判断是否是当日反馈。
最开始实现时候想法很简单,只考虑到了双休日,就设定如果是双休日的告警事件,在周一时候反馈就认为是当日反馈,当时是这么实现的:
如果是周六,反馈日期增加2,如果是周日,反馈日期增加1

case dayofweek(alarm_date)
	when 7 then date_add(fb_date,2)
	when 0 then date_add(fb_date,1)
else fb_date end as fb_date

但是在实际使用中,发现了存在节假日的卡点,尤其是上半年的节假日比较多,所以不过滤节假日对结果有很大的影响,另外,对于一些双休日,也可能是工作日串休。

三、过滤节假日

为什么会说这个问题是连续登录问题的变形呢?我们想一想,节假日是不是连续的?无论是双休还是节假日,都是连续的日期。那么这个问题就变成了,我们要分辨出哪些是节假日?哪些是工作日?
这种实现的思路我想到的有两个

思路一

编写UDF,在jar包中维护一个文件,文件可以记录节假日的日期,写一个自定义的UDF实现这个功能
这个方法可以实现,但是过程会有一些繁琐,但是好处是可以复用性强,一次编写,到处使用

思路二

维护一张节假日的维表,通过一些sql逻辑实现,优点是实现过程不繁琐,缺点是复用性不强。对于缺点,其实可以把结果输出到一张维表中使用,同时还可以增加一些其他维度,因为生产环境中类似这种时间节假日的维度使用的还挺多。

四、功能实现

采用思路二实现,维护一张维表,维表中记录了日期是否为节假日,实现方式也有两种

方式1:等差求解

回忆连续登录问题的解法,求等差,找到连续的天数,按照正序排序,返回连续天数的下一天,就是需要的结果

流程图如下:

sql server 判断是否为工作日 sql工作日节假日判断_sql server 判断是否为工作日

日期

是否节假日

返回值

06-01

1

06-03

06-02

1

06-03

06-03

0

06-03

06-04

1

06-05

06-05

0

06-05

1	select 
2	  log_date, 
3	  date_add(log_date, rn) next_work_day 
4	from ( 
5	select 
6	  log_date, 
7	  row_number() 
8	  over(partition by start_day order by log_date desc) rn 
9	from ( 
10	select 
11	  log_date, 
12	  date_sub(log_date, rn) start_day 
13	from( 
14	select 
15	  log_date, 
16	  row_number() 
17	  over(order by log_date) rn 
18	from ( 
19	select 
20	  log_date 
21	from 
22	  tmp_bdp.tmp_log_date 
23	) t1 
24	) t2 
25	) t3 
26	) t4
方式2:前后相减

也是模拟连续登录的方式,找到连续天数的下一天,就是要返回的值

1	select 
2	  log_date, 
3	  max(log_date) 
4	  over(partition by flag order by log_date) next_day 
5	from ( 
6		select 
7		  log_date, 
8		  sum(if(diff_date > 1, 1, 0)) 
9		  over(order by log_date) flag 
10		from ( 
11			select  
12			  log_date, 
13			  datediff(log_date, lag_date) diff_date 
14			from ( 
15				select 
16				  `date` as log_date, 
17				  lag(`date`, 1, '1970-01-01')  
18				  over(order by `date`) lag_date 
19				from 
20				  bili_dim.dim_date_info_d 
21				where year(`date`) = 2022 and holiday_type <> 0 
22			) t1 
23		) t2 
24	) t3