DoytoQuery 聚合查询方案示例详解

 更新时间:2022年12月27日 16:39:46   作者:f0rb  
这篇文章主要为大家介绍了DoytoQuery 聚合查询方案示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

1. 引言

聚合查询是数据库提供的另一种常用的用于数据的统计和计算的查询功能,它通过提供一系列聚合函数来汇总来自多个行的信息。

DoytoQuery采用字段前缀映射的方式来将字段名映射为聚合函数,再配合@GroupBy注解,Having接口以及Query对象,完成整条聚合查询语句的映射。

2. 聚合查询映射

2.1. 前缀映射

聚合函数是聚合查询的核心功能,常用的聚合函数有以下几种:

  • count
  • sum
  • max
  • min
  • avg
  • first
  • last
  • stddev_pop
  • stddev_samp
  • stddev
  • addToSet
  • push

使用聚合函数查询出来的数据也需要占用一列,这一列数据也需要映射到POJO对象的一个字段。我们可以利用这一特性,在定义POJO对象的字段时,采用聚合函数关键字加上大驼峰格式的列名即可。这个字段既可以用于映射查询语句,又可以保存返回的数据,一举两得。比如我们想统计分数列score的平均值,我们将字段名定义为avgScore,在构造查询语句时,这个字段就会被映射为avg(score) AS avgScore,依此类推。

2.2. 分组聚合

聚合查询中少不了针对部分表列进行分组聚合,这些用于分组的表列通常也需要查询出来, 于是便可以将这些表列也定义到POJO对象中,同时需要与其他的聚合字段加以区别。DoytoQuery中采用添加@GroupBy注解的方式进行区分。

@Target(FIELD)
@Retention(RUNTIME)
public @interface GroupBy {
}

示例:

@Entity(name = "t_score")
private class ScoreGroupByStudentView {
    @GroupBy
    private Long studentId;
    private Double avgScore;
}

上述对象会被映射为如下SQL语句:

SELECT student_id AS studentId, avg(score) AS avgScore FROM t_score GROUP BY student_id

2.3. HAVING

SQL语句使用HAVING子句针对聚合后的数据进行筛选过滤。DoytoQuery将实现了Having接口的对象映射为HAVING子句。字段的映射同时采用前缀映射和后缀映射方式。例如在实现了Having接口的对象中定义的字段avgScoreGe将被映射为HAVING avg(score) >= ?

public interface Having extends Serializable {
}

2.4. 动态查询

动态查询WHERE语句的构造复用DoytoQuery中的动态查询方案

另外,为Query对象提供了一个AggregationQuery接口用于构造HAVING条件。

public interface AggregationQuery extends DoytoQuery {
    Having getHaving();
}

2.5. 查询接口定义

最后,DoytoQuery中关于聚合查询的接口定义如下:

public interface DataQueryClient {
    // ...
    <V, Q extends AggregationQuery>
    List<V> aggregate(Q query, Class<V> viewClass);
}

3. 完整示例

现在我们来通过一个完整的示例,来演示DoytoQuery如何来实现对表t_student_score的聚合查询功能。

create table t_student_score
(
    id          bigint generated by default as identity primary key,
    school_term varchar(100)   not null,
    subject     varchar(100)   not null,
    student_no  varchar(10)    not null,
    score       numeric(10, 2) not null,
    is_deleted  boolean        not null default false
);

创建StudentScoreStatView用于映射聚合函数和分组字段。

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity(name = "t_student_score")
public class StudentScoreStatView {
    @SuppressWarnings("java:S116")
    @GroupBy
    private String school_term;
    @GroupBy
    private String subject;
    private Integer countScore;
    private Double minScore;
    private Double maxScore;
    private Double avgScore;
}

创建StudentScoreHaving用于映射HAVING子句。

public class StudentScoreHaving implements Having {
    private Integer countGt;
}

创建StudentScoreStatViewQuery用于动态查询条件。

public class StudentScoreStatViewQuery extends PageQuery implements AggregationQuery {
    private String schoolTermGe;
    private List<String> subjectIn;
    private Double scoreGe;
    private Boolean isDeleted;
    private StudentScoreHaving studentScoreHaving;
    @Override
    public Having getHaving() {
        return studentScoreHaving;
    }
}

最后创建一个单元测试来进行验证。

@SpringBootTest
class StudentScoreStatTest {
    @Resource
    private DataQueryClient dataQueryClient;
    @Test
    void aggregateStudentScore() {
        StudentScoreStatViewQuery statQuery = StudentScoreStatViewQuery
                .builder()
                .schoolTermGe("2000")
                .subjectIn(Arrays.asList("Chinese", "Math", "English"))
                .scoreGe(60.)
                .isDeleted(false)
                .studentScoreHaving(StudentScoreHaving.builder().countGt(1).build())
                .sort("school_term,asc;subject,asc")
                .build();
        SqlAndArgs sqlAndArgs = RelationalQueryBuilder.buildSelectAndArgs(statQuery, StudentScoreStatView.class);
        assertThat(sqlAndArgs.getSql()).isEqualTo(
                "SELECT school_term, subject, count(score) AS countScore, min(score) AS minScore, " +
                        "max(score) AS maxScore, avg(score) AS avgScore " +
                        "FROM t_student_score " +
                        "WHERE school_term >= ? AND subject IN (?, ?, ?) AND score >= ? AND is_deleted = ? " +
                        "GROUP BY school_term, subject " +
                        "HAVING count(*) > ? " +
                        "ORDER BY school_term asc, subject asc");
        assertThat(sqlAndArgs.getArgs()).containsExactly("2000", "Chinese", "Math", "English", 60., false, 1);
        List<StudentScoreStatView> statList = dataQueryClient.aggregate(statQuery, StudentScoreStatView.class);
        assertThat(statList).hasSize(3)
                            .first().isEqualTo(new StudentScoreStatView("2022", "Chinese", 3, 85., 93., 89.));
    }
}

完整代码请查看 GitHub

4. 总结

本文详细介绍了DoytoQuery中的聚合查询方案,包括聚合函数的前缀映射,@GroupBy注解,Having接口以及动态查询构造等方式,将对象映射为聚合查询语句,用以完成聚合查询,更多关于DoytoQuery 聚合查询方案的资料请关注脚本之家其它相关文章!

相关文章

  • 详解Java递归实现树形结构的两种方式

    详解Java递归实现树形结构的两种方式

    在开发的过程中,很多业务场景需要一个树形结构的结果集进行前端展示,也可以理解为是一个无限父子结构,常见的有报表指标结构、菜单结构等,这篇文章主要介绍了Java递归实现树形结构的两种方式,需要的朋友可以参考下
    2022-10-10
  • 深入解析堆排序的算法思想及Java代码的实现演示

    深入解析堆排序的算法思想及Java代码的实现演示

    堆排序基于二叉堆结构即完全二叉树,可利用最大堆和最小堆的组建方式来进行排序,这里就来深入解析堆排序的算法思想及Java代码的实现演示
    2016-06-06
  • Spring Security OAuth2 实现登录互踢的示例代码

    Spring Security OAuth2 实现登录互踢的示例代码

    这篇文章主要介绍了Spring Security OAuth2实现登录互踢的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-04-04
  • 浅谈Maven 项目中依赖的搜索顺序

    浅谈Maven 项目中依赖的搜索顺序

    这篇文章主要介绍了浅谈Maven 项目中依赖的搜索顺序,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-09-09
  • Spring boot中PropertySource注解的使用方法详解

    Spring boot中PropertySource注解的使用方法详解

    这篇文章主要给大家介绍了关于Spring boot中PropertySource注解的使用方法,文中通过示例代码介绍的非常详细,对大家学习或者使用Spring boot具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧。
    2017-12-12
  • springboot 整合 nacos 配置实现多个环境不同配置

    springboot 整合 nacos 配置实现多个环境不同配置

    本文介绍了Nacos配置中心的优势,包括与Apollo的性能对比,Nacos服务端的安装与配置,以及如何在SpringBoot项目中集成Nacos进行多环境配置,提供了详细的步骤,包括下载、安装、配置中心的创建和项目集成,旨在帮助开发者更好地使用Nacos进行项目配置管理
    2024-09-09
  • Mybatis查询时,区分大小写操作

    Mybatis查询时,区分大小写操作

    这篇文章主要介绍了Mybatis查询时,区分大小写操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • java isPalindrome方法在密码验证中的应用

    java isPalindrome方法在密码验证中的应用

    这篇文章主要为大家介绍了java isPalindrome方法在密码验证中的简单应用技巧,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12
  • 使用@Autowired注解引入server服务层方法时报错的解决

    使用@Autowired注解引入server服务层方法时报错的解决

    这篇文章主要介绍了使用@Autowired注解引入server服务层方法时报错的解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • logback ThrowableProxyConverter类源码流程解析

    logback ThrowableProxyConverter类源码流程解析

    这篇文章主要为大家介绍了logback ThrowableProxyConverter类源码流程解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12

最新评论