java实现日报表、月报表统计,没数据补0

产品需求:

1、日报表

image.png

2、月报表

image.png

需求点: 前端传日期或月份区间,当数据库中指定的日期或月份没数据时也需要界面显示,但领取人数和使用人数需要自动补齐0;
举例:2020-11-28、2020-11-29,数据库中没数据,但也需要在界面显示,领取人数和使用人数为0;

image.png

思路很重要

1、首先根据前端传来的时间区间,查询出区间中所有的日期或月份;
2、然后循环日期或月份和数据库查询返回的List<实体对象>的日期或月份进行匹配;
2.1、不存在则在List<实体对象>中新增一条实体对象数据;
3、最后统一把处理后的List<实体对象>返回前端;

sql语句(后面Mapper.xml中全部详细列出)

注:这里是Mysql数据库,以日报表为例,** 月报表则是将 DATE_FORMAT格式修改为 %Y-%m 即可 **

<!-- 根据日期分组查询 “领取人数” 和 “使用人数”,然后将两个Sql查询结果汇总 -->

SELECT
    t.days,
    sum( t.receiveQty ) AS receiveQty,
    sum( t.userQty ) AS userQty 
FROM
    (
        <!-- 领取人数 -->
        SELECT
            DATE_FORMAT( r.created_time, '%Y-%m-%d' ) AS days,
            count( r.id ) AS receiveQty,
            0 AS userQty 
        FROM
            dg_experience_receive r
            LEFT JOIN dg_experience_order o ON r.user_id = o.user_id 
        WHERE
            DATE_FORMAT( r.created_time, '%Y-%m-%d' ) >= '2020-11-01' 
            AND DATE_FORMAT( r.created_time, '%Y-%m-%d' ) <= '2020-12-16' 
        GROUP BY
            days 

        UNION ALL

        <!-- 使用人数 -->
        SELECT
            DATE_FORMAT( r.created_time, '%Y-%m-%d' ) AS days,
            0 AS receiveQty,
            count( r.id ) AS userQty 
        FROM
            dg_experience_receive r
            JOIN dg_experience_order o ON r.user_id = o.user_id 
        WHERE
            r.is_used = 1 
            AND DATE_FORMAT( r.created_time, '%Y-%m-%d' ) >= '2020-11-01' 
            AND DATE_FORMAT( r.created_time, '%Y-%m-%d' ) <= '2020-12-16' 
        GROUP BY
            days 
    ) t 
GROUP BY
    days 
ORDER BY
    days DESC;

请求实体

@Data
public class DepositExperienceDayReq {
    /**
     * 开始日期
     */
    @NotBlank(message = "起始日期不能为空!")
    private String startDate;

    /**
     * 结束日期
     */
    @NotBlank(message = "截至日期不能为空!")
    private String endDate;
}

返回实体

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DepositExperienceDayRes {
    /**
     * 日期
     */
    private String days;

    /**
     * 领取人数
     */
    private Long receiveQty;

    /**
     * 使用人数
     */
    private Long userQty;
}

Controller

/**
     * 体验金日报表--查询
     */
    @PostMapping("/experienceDay/list")
    public ResponseData listExperienceDayByReq(@Valid @RequestBody DepositExperienceDayReq experienceDayReq){
        return ResponseData.success(experienceOrderService.listExperienceDayByReq(experienceDayReq));
    }

    /**
     * 体验金月报表--查询
     */
    @PostMapping("/experienceMonth/list")
    public ResponseData listExperienceMonthByReq(@Valid @RequestBody DepositExperienceDayReq experienceDayReq){
        return ResponseData.success(experienceOrderService.listExperienceMonthByReq(experienceDayReq));
    }

Service

/**
     * 运营报表--体验金日报表--查询
     * @param experienceDayReq
     * @return
     */
    List<DepositExperienceDayRes> listExperienceDayByReq(DepositExperienceDayReq experienceDayReq);

    /**
     * 运营报表--体验金月报表--查询
     * @param experienceDayReq
     * @return
     */
    List<DepositExperienceDayRes> listExperienceMonthByReq(DepositExperienceDayReq experienceDayReq);

ServiceImpl(这里是重点,需要看一下)

注: DateUtil使用的是 hutool-core-5.0.6.jar

    /**
     * 运营报表--体验金日报表--查询
     * @param experienceDayReq
     * @return
     */
    @Override
    public List<DepositExperienceDayRes> listExperienceDayByReq(DepositExperienceDayReq experienceDayReq) {

        // 首先根据前端传来的时间区间,查询出区间中所有的日期;
        List<Date> lDate = findDates(DateUtil.parseDate(experienceDayReq.getStartDate()), DateUtil.parseDate(experienceDayReq.getEndDate()), Calendar.DAY_OF_MONTH);
        if (CollectionUtils.isEmpty(lDate)){
            return null;
        }
        List<DepositExperienceDayRes> experienceDayResList = baseMapper.listExperienceDayByReq(experienceDayReq);
        for (Date date : lDate){
            // 当前日期不存在则新增
            String dateStr = DateUtil.format(date, "yyyy-MM-dd");
            // 进行匹配
            if(!experienceDayResList.stream().filter(item -> dateStr.equals(item.getDays())).findAny().isPresent()){
                DepositExperienceDayRes experienceDayRes = DepositExperienceDayRes.builder()
                        .days(dateStr)
                        .receiveQty(0L)
                        .userQty(0L)
                        .build();
                experienceDayResList.add(experienceDayRes);
            }
        }
        List<DepositExperienceDayRes> collect = experienceDayResList.stream().sorted(Comparator.comparing(DepositExperienceDayRes::getDays).reversed()).collect(Collectors.toList());
        return collect;
    }


    /**
     * 运营报表--体验金月报表--查询
     * @param experienceDayReq
     * @return
     */
    @Override
    public List<DepositExperienceDayRes> listExperienceMonthByReq(DepositExperienceDayReq experienceDayReq) {
        // 首先根据前端传来的时间区间,查询出区间中所有的月份;
        DateTime startDate = DateUtil.parse(experienceDayReq.getStartDate(), "yyyy-MM");
        DateTime endDate = DateUtil.parse(experienceDayReq.getEndDate(), "yyyy-MM");
        List<Date> lDate = findDates(startDate, endDate, Calendar.MONTH);
        if (CollectionUtils.isEmpty(lDate)){
            return null;
        }
        List<DepositExperienceDayRes> experienceDayResList = baseMapper.listExperienceMonthByReq(experienceDayReq);
        for (Date date : lDate){
            // 当前日期不存在则新增
            String dateStr = DateUtil.format(date, "yyyy-MM");
            // 进行匹配
            if(!experienceDayResList.stream().filter(item -> dateStr.equals(item.getDays())).findAny().isPresent()){
                DepositExperienceDayRes experienceDayRes = DepositExperienceDayRes.builder()
                        .days(dateStr)
                        .receiveQty(0L)
                        .userQty(0L)
                        .build();
                experienceDayResList.add(experienceDayRes);
            }
        }
        List<DepositExperienceDayRes> collect = experienceDayResList.stream().sorted(Comparator.comparing(DepositExperienceDayRes::getDays).reversed()).collect(Collectors.toList());
        return collect;
    }

    /**
     * 获取指定时间区间的所有数据(包含日期和月份)
     * @param dBegin
     * @param dEnd
     * @param rule 日历规则 如:Calendar.DAY_OF_MONTH
     * @return
     */
    public static List<Date> findDates(Date dBegin, Date dEnd, int rule) {
        List lDate = new ArrayList();
        if (dEnd.before(dBegin)){
            return lDate;
        }
        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(rule, 1);
            lDate.add(calBegin.getTime());
        }
        return lDate;
    }

Mapper.xml

 <!-- 日报表 -->
<select id="listExperienceDayByReq"
            resultType="com.dg.mall.financial.vo.res.report.operation.DepositExperienceDayRes">
        SELECT
            t.days,
            sum(t.receiveQty) as receiveQty,
            sum(t.userQty) as userQty
        FROM (
            SELECT
                DATE_FORMAT(r.created_time , '%Y-%m-%d' ) AS days,
                count(r.id) as receiveQty,
                0 as userQty
            FROM dg_experience_receive r
            LEFT JOIN dg_experience_order o on r.user_id = o.user_id
            <where>
                <if test="experienceDayReq.startDate != null and experienceDayReq.startDate != ''">
                    <![CDATA[ AND DATE_FORMAT(r.created_time, '%Y-%m-%d') >= #{experienceDayReq.startDate} ]]>
                </if>
                <if test="experienceDayReq.endDate != null and experienceDayReq.endDate != ''">
                    <![CDATA[ AND DATE_FORMAT(r.created_time, '%Y-%m-%d') <= #{experienceDayReq.endDate} ]]>
                </if>
            </where>
            GROUP BY days

            UNION ALL

            SELECT
                DATE_FORMAT(r.created_time , '%Y-%m-%d' ) AS days,
                0 as receiveQty,
                count(r.id) as userQty
            FROM dg_experience_receive r
            JOIN dg_experience_order o on r.user_id = o.user_id
            <where>
                AND r.is_used = 1
                <if test="experienceDayReq.startDate != null and experienceDayReq.startDate != ''">
                    <![CDATA[ AND DATE_FORMAT(r.created_time, '%Y-%m-%d') >= #{experienceDayReq.startDate} ]]>
                </if>
                <if test="experienceDayReq.endDate != null and experienceDayReq.endDate != ''">
                    <![CDATA[ AND DATE_FORMAT(r.created_time, '%Y-%m-%d') <= #{experienceDayReq.endDate} ]]>
                </if>
            </where>
            GROUP BY days
        ) t
        GROUP BY days
        order by days desc
    </select>

    <!-- 月报表 -->
    <select id="listExperienceMonthByReq"
            resultType="com.dg.mall.financial.vo.res.report.operation.DepositExperienceDayRes">
        SELECT
        t.days,
        sum(t.receiveQty) as receiveQty,
        sum(t.userQty) as userQty
        FROM (
        SELECT
        DATE_FORMAT(r.created_time , '%Y-%m' ) AS days,
        count(r.id) as receiveQty,
        0 as userQty
        FROM dg_experience_receive r
        LEFT JOIN dg_experience_order o on r.user_id = o.user_id
        <where>
            <if test="experienceDayReq.startDate != null and experienceDayReq.startDate != ''">
                <![CDATA[ AND DATE_FORMAT(r.created_time, '%Y-%m') >= #{experienceDayReq.startDate} ]]>
            </if>
            <if test="experienceDayReq.endDate != null and experienceDayReq.endDate != ''">
                <![CDATA[ AND DATE_FORMAT(r.created_time, '%Y-%m') <= #{experienceDayReq.endDate} ]]>
            </if>
        </where>
        GROUP BY days

        UNION ALL

        SELECT
        DATE_FORMAT(r.created_time , '%Y-%m' ) AS days,
        0 as receiveQty,
        count(r.id) as userQty
        FROM dg_experience_receive r
        JOIN dg_experience_order o on r.user_id = o.user_id
        <where>
            AND r.is_used = 1
            <if test="experienceDayReq.startDate != null and experienceDayReq.startDate != ''">
                <![CDATA[ AND DATE_FORMAT(r.created_time, '%Y-%m') >= #{experienceDayReq.startDate} ]]>
            </if>
            <if test="experienceDayReq.endDate != null and experienceDayReq.endDate != ''">
                <![CDATA[ AND DATE_FORMAT(r.created_time, '%Y-%m') <= #{experienceDayReq.endDate} ]]>
            </if>
        </where>
        GROUP BY days
        ) t
        GROUP BY days
        order by days desc
    </select>

PostMan结果展示:

image.png

image.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容