MySQL 超出月份最大日期(工作总结)

6 篇文章 0 订阅

前几天帮同事修改了一个bug,这个bug是怎么造成的呢。先来看需求,系统需要统计某个月份的数据。很简单的一个需求。 

同事的写的MySQL语句

SELECT
        REPLACE(FORMAT(sum(count_value),2), ',', '') as value,
        <if test="type == 'day'">
            count_date as `time`
        </if>
        <if test="type == 'hour'">
            count_time as `time`
        </if>
        <if test="type == 'month'">
            DATE_FORMAT(count_date, '%Y-%m') as `time`
        </if>
        <if test="type == 'year'">
            DATE_FORMAT(count_date, '%Y') as `time`
        </if>
        FROM
        device_value
        WHERE  count_date BETWEEN #{startTime} AND #{endTime}
        and node_id in
        <foreach collection="nodeIds" separator="," open="(" close=")" item="nodeId">
            #{nodeId}
        </foreach>
        GROUP BY
        <if test="type == 'day'">
             count_date
        </if>
        <if test="type == 'hour'">
            count_time
        </if>
        <if test="type == 'month'">
            DATE_FORMAT(count_date, '%Y-%m')
        </if>
        <if test="type == 'year'">
             DATE_FORMAT(count_date, '%Y')
        </if>
        <if test="type == 'day'">
            order by  count_date
        </if>
        <if test="type == 'hour'">
            order by  count_time
        </if>
        <if test="type == 'month'">
            order by  DATE_FORMAT(count_date, '%Y-%m')
        </if>

sql也很简单,就是通过传递不同的type从时间的不同角度去统计出device_value这张表中的在startTime和endTime这时间段内的value值之和。

然后就是Java代码了,具体就不展示了。总结来说他如果要查询六月的数据,他就是将前端传递过来的2024-06这样一个字符串拼接上一个01和31。然后就传递到xml中查询。运行时MySQL代码:

SELECT REPLACE
	( FORMAT( sum( count_value ), 2 ), ',', '' ) AS VALUE,
	count_date AS `time` 
FROM
	device_everyday_count_value 
WHERE
	count_date BETWEEN '2024-06-01' AND '2024-06-31'
	AND node_id IN ( 'KTXTYCNH' ) 
GROUP BY
	count_date 
ORDER BY
	count_date

看一下查询结果

                        

你会发现是没有结果的,实际上6月是有数据的,但是6月确实没有31号的只有30号,我将他写的31改为30后再此运行同样MySQL代码结果如下

                                

讲到这里大家应该也发现了代码问题之处了,就是日常超出了范围导致的查询没有结果。在前端展示的时候并不会报错,只是小于31天的数据是没有值的。

最后我将他的Java代码在传递日期的时候给修改了,通过LocalTime来获取某一年的某一月的日期的开始以及结束日期。

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate startTime = LocalDate.parse(date, formatter);
        String endDate = date;
        if("month".equals(dateType)){
            date = startTime.with(TemporalAdjusters.firstDayOfMonth()).toString();
            endDate = startTime.with(TemporalAdjusters.lastDayOfMonth()).toString();
        }else if("year".equals(dateType)){

            date = startTime.with(TemporalAdjusters.firstDayOfYear()).toString();
            endDate = startTime.with(TemporalAdjusters.lastDayOfYear()).toString();
        }
        事后我有问过他,我问他当时怎么想的,为什么会当时会这样写代码呢?
他跟我说:我写的时候觉得没什么不对啊,我当时觉得每个月的月份开始日期都是01,然后结束最大就是31我拼接出来的日期就算是6月只有30天但是我31也没什么问题也包含了30号的日期,并不会遗漏数据所以就这么写了。
然后我又问他:你当时写的时候没去测一下这种写法在特殊的月份的时候查询会不会出现问题呢。
他说:我没有,我当时写来并没有调用接口的时候并没有报错,并且有数据我就没管了。
他当时写的时候是5月份所以并不会有什么问题。至此我也不好再多说什么

 我只能说善用现有的工具,别写魔法数字和魔法字符串。

路漫漫其修远兮,吾将上下而求索!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值