需求:做管理后台报表时,给定一个日期范围,查出库中这个日期范围内的每一天数据,库中不存在的日期对应数据要补0

方法一:

获取每一天的sql语句:

SELECT
	date_add( date_sub(#{startDate},interval 1 day), INTERVAL ( cast( help_topic_id AS signed INTEGER ) + 1 ) day ) days 
FROM mysql.help_topic 
WHERE
	help_topic_id < DATEDIFF(#{endDate},date_sub(#{startDate},interval 1 day))
ORDER BY
	help_topic_id

对于表中不存在的日期,我们用右外连接即可解决!!!当然左连接也可以,看你的主表是谁。

注:我们不一定非要用表 mysql.help_topic,这里只是用到了它的id,我们可自行建一个有id列的表,但是自己建的表id不能自增,且id必须从0开始(为什么id不能自增:id自增就不能从0开始,只能从1开始;为什么id必须从0开始:如果id没有从0开始,那么所得到的日期列表就是#{startDate}+1 ~ #{endDate})

上面这种sql呢有两个明显的缺陷:首先你可能没有权限访问 mysql 库里的表 help_topic,那你就的自行建张表;其次是 当你的时间段范围非常大,而mysql.help_topic/自己建的表 表里没有那么多的id个数,就不能满足你的需求,那你可能就要写存储过程、视图、还有很多的方法。

案例:

因为我没权限所以用不到存储过程,而且时间段范围也就一个月,所以上面的sql也就满足了

这是我库中的数据:(表中不存在日期21、22、24、25)

右外连接查询解决问题:

方法二:

select adddate((select min(date) from t_pivotal_behavior_report),t2.i*10+t1.i*10 + t0.i) dateStr from
 (select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
 (select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
 (select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2
;

再用左连接或有链接即可查出不存在的日期 

进而可衍生出:

这段日期内的某几天

select * from (
select subdate("2022-03-04", t1.i*10+t0.i) dateStr from
 (select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
 (select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1
 ) a where a.dateStr>=DATE_SUB("2022-03-04", INTERVAL 14 DAY) and dateStr<="2022-03-04"
;

方法三:

思路:得到你要查询日期范围,然后使用Java的方法罗列出日期段内的每一天,然后用Java把它拼接成SQL语句,然后使用mybatis的 ${} 接收,然后左连接或右连接查询出不存在的日期

示例:我要查库中最小日到今天这段日期内不存在的日期:

1.查出库中最小日期,

2.罗列最小日期到今天的每一天:

    /**
     * 获取每一天日期
     * @param dBegin
     * @param dEnd
     * @return
     */
    public static List<Date> findDates(Date dBegin, Date dEnd)  {
        Date tomorrow = DateUtil.getMinDateOfDay(DateUtil.getNextDate(new Date()));

        List lDate = new ArrayList();
        lDate.add(dBegin);
        Calendar calBegin = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        calBegin.setTime(dBegin);
        Calendar calEnd = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        calEnd.setTime(dEnd);
        // 测试此日期是否在指定日期之后
        while (dEnd.after(calBegin.getTime())) {
            // 根据日历的规则,为给定的日历字段添加或减去指定的时间量
            calBegin.add(Calendar.DAY_OF_MONTH, 1);
            if(calBegin.getTime().getTime() < tomorrow.getTime())
                lDate.add(calBegin.getTime());
        }
        return lDate;
    }

3.使用select和union将日期集合拼接成SQL语句

    //将date集合拼接成SQL语句
    private static String getDateListSqlByMinDateAndToday(String minDate) {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        Date parse = null;
        //日期类型转化
        try {
            parse = df.parse(minDate);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        //得到每一天日期
        List<Date> dates = DateUtil.findDates(parse, new Date());
        if (dates == null || dates.size() ==0) {
            return null;
        }

        //SQL凭借
        String sql="";
        for (Date date : dates) {
            //把每个日期用引号引起来,Java需要字符转义
            sql+="select \""+df.format(date)+"\" as `date` union ";
        }
        //去掉空格
        sql=sql.trim();
        //去掉最后一个union
        sql=sql.substring(0,sql.length()-"union".length());

        return sql;
    }

例如得到拼接的SQL:

select "2021-12-01" as `date` union select "2021-12-02" as `date` union select "2021-12-03" as `date` union select "2021-12-04" as `date` union select "2021-12-05" as `date` union select "2021-12-06" as `date` union select "2021-12-07" as `date` union select "2021-12-08" as `date` union select "2021-12-09" as `date` union select "2021-12-10" as `date` 

4.将得到的SQL传给mybatis

5.mybatis接收:

select t1.`date` from ( ${dateListSql} ) t1
			left join (select `date` from t_pivotal_behavior_report where `type`=#{type} and app_type=#{appType} GROUP BY `date`) t2
			on t1.`date`=t2.`date`
		where t2.`date` is null

 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐