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 聚合查询方案的资料请关注脚本之家其它相关文章!
相关文章
Spring Security OAuth2 实现登录互踢的示例代码
这篇文章主要介绍了Spring Security OAuth2实现登录互踢的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2020-04-04Spring boot中PropertySource注解的使用方法详解
这篇文章主要给大家介绍了关于Spring boot中PropertySource注解的使用方法,文中通过示例代码介绍的非常详细,对大家学习或者使用Spring boot具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧。2017-12-12springboot 整合 nacos 配置实现多个环境不同配置
本文介绍了Nacos配置中心的优势,包括与Apollo的性能对比,Nacos服务端的安装与配置,以及如何在SpringBoot项目中集成Nacos进行多环境配置,提供了详细的步骤,包括下载、安装、配置中心的创建和项目集成,旨在帮助开发者更好地使用Nacos进行项目配置管理2024-09-09使用@Autowired注解引入server服务层方法时报错的解决
这篇文章主要介绍了使用@Autowired注解引入server服务层方法时报错的解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2021-11-11logback ThrowableProxyConverter类源码流程解析
这篇文章主要为大家介绍了logback ThrowableProxyConverter类源码流程解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪2023-12-12
最新评论