mysql中YEARWEEK跨年引发的线上问题

    问题源于一个测试小哥敏捷环境提的bug,简单描述一下场景,方便理解问题.现在有一个课程表查询功能,支持按照周为单位进行多个上周或是多个下周的课程表查询.支持复制当前一周课程表到下周,当天是2022.1.2,在当天复制本周课程表到下周之后切换到下周查询不到复制的课程信息.从数据库看数据库入表操作没有问题,创建时间是当天。
    定位问题发现在于:YEARWEEK()函数.
    业务中根据课程创建时间所在的周与当前日期时间所属周做比较,如果相同则会查询出课程信息,按照课程创建时间查询伪代码如下:

select * from course_table where
YEARWEEK(CURRENT_DATE(),1)+#{intervalWeek}=YEARWEEK(create_time,1) 

intervalWeek表示课程表查询页面选择的周数,0表示查询当前时间周,1表示当前时间下一周,以此类推;-1表示当前时间上周,以此类推;2022.1.2所在周选择下一周时intervalWeek传递参数为1.
    问题出现在周数加减上(2021-01-02所在周查询下一周课表时周数信息不一致导致).

SELECT  YEARWEEK('2022-01-02',1)+1  -- 查询结果:202153

此时查询出来的周数信息加1之后是:202153,表示是2021年第53个周.但是实际上2021年是只有52个周(按照2022.01.03查询).

SELECT  YEARWEEK('2022-01-03',1)  -- 查询结果:202201

解决方案
    按照mysql中提供的日期函数进行加减操作,新增类型(type为1时加指定周;为2时减指定周),减时用DATE_SUB,加时用DATE_ADD,当前周为0时两种方式都支持.伪代码如下:

select * from course_table  
<where>
 <if test="type==1">
      and YEARWEEK(DATE_FORMAT(start_time,'%Y-%m-%d' ),1) = YEARWEEK(DATE_ADD(CURRENT_DATE(),INTERVAL #{weekDay} WEEK),1)
 </if>
 <if test="type==2">
      and  YEARWEEK(DATE_FORMAT(start_time,'%Y-%m-%d' ),1) = YEARWEEK(DATE_SUB(CURRENT_DATE(),INTERVAL #{weekDay} WEEK),1)
 </if>
</where>

     至于为何不对当前时间每年最后一周单独做处理的原因如下:查询近几年数据发现,以每年的第一个星期日来看,mysql查询出来的最后一周有的是52周,有的是53周,不便于做判断.

  	select YEARWEEK('2022-01-02',1) -- 查询结果:202152  
	select YEARWEEK('2022-01-03',1) -- 查询结果:202201  
	
	select YEARWEEK('2021-01-03',1) -- 查询结果:202053 
	select YEARWEEK('2021-01-04',1) -- 查询结果:202101
	
	select YEARWEEK('2019-12-29',1) -- 查询结果:201952
	select YEARWEEK('2020-01-05',1) -- 查询结果:202001

	select YEARWEEK('2019-12-29',1) -- 查询结果:201852
	select YEARWEEK('2019-01-06',1) -- 查询结果:201901
	

    总结:平常使用mysql函数要多关注临界值,不然平常没有问题,特殊情况就会出现大问题,上面的场景如果不是跨年也不会暴露出问题。
    YEARWEEK()以及DATE_SUB()函数以及其他常用函数参考: mysql常用函数使用场景总结(持续更新)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卖柴火的小伙子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值