java - 如何使用querydsl从子查询平均集合中获取总平均值
问题描述
我有下一个实体:
@Entity
@Table(name = "search_request_items")
public class SearchRequestItem extends LongIdEntity {
@Column(name = "date")
private Instant date;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
@Column(name = "result_count")
private Long resultCount;
/**
* Request's text.
*/
@Column(name = "request")
private String request;
/**
* Request's quality. It may take 0 or 1.
*/
@Column(name = "quality")
private Integer quality;
...
}
然后我有下一个 queryDSL 查询,它返回按请求文本分组的质量平均值和用户计数的集合:
public JPAQuery<Tuple> prepareTotalQuery() {
QSearchRequestItem requestItem = QSearchRequestItem.searchRequestItem;
QUser user = QUser.user;
NumberExpression<Double> qualityAvgExpression = requestItem.quality.avg();
NumberExpression<Long> qualityCountExpression = requestItem.user.countDistinct();
JPAQuery<Tuple> query = queryFactory
.select(qualityAvgExpression, qualityCountExpression)
.from(requestItem)
.leftJoin(requestItem.user, user)
.groupBy(requestItem.request)
.having(qualityAvgExpression.isNotNull(),
qualityCountExpression.gt(2));
return query;
}
但我需要在这个集合上返回总平均值,就像这个本机查询一样:
select avg(n1.avg_quality)
from (select count(distinct user_id), avg(quality) as avg_quality
from search_request_items
group by request
having avg(quality) is not null and count(distinct user_id) > 2
) n1;
那么,如何更新我的 querydsl 查询以获得这个结果呢?
解决方案
这里的问题是您正在使用 JPA,而 JPA 不允许在 from 子句中使用子查询作为连接目标。
Blaze-Persistence是 JPA 的扩展,并与 Hibernate 很好地集成。它将公用表表达式和子选择(甚至横向)连接添加到 JPQL。Blaze-Persistence 还具有Querydsl 集成,允许您编写如下查询:
List<Number> fetch = new BlazeJPAQuery<>(entityManager, cbf)
.with(cteType, new BlazeJPAQuery<>()
.bind(cteType.avgQuantity, requestItem.quality.avg())
.from(requestItem)
.leftJoin(requestItem.user, user)
.groupBy(requestItem.request)
.having(qualityAvgExpression.isNotNull(), qualityCountExpression.gt(2))))
)
.select(cteType.avgQuantity.avg())
.from(cteType)
.fetch();
但是,对于普通的 JPA 和 Hibernate,没有简单的方法可以做到这一点。
但是,如果您只是对一组数字进行平均,这些数字对于通过 JDBC 序列化并不密集并且不会受到潜在的 N+1 问题的影响,我建议您只需在内存中执行最后的平均步骤:
queryFactory
.select(qualityCountExpression)
.from(requestItem)
.leftJoin(requestItem.user, user)
.groupBy(requestItem.request)
.having(qualityAvgExpression.isNotNull(),
qualityCountExpression.gt(2))
.stream()
.collect(Collectors.averagingDouble(i -> i.doubleValue()))
推荐阅读
- angular - Angularfire2 我正在尝试获取 Angular Fire 文档的字段名称
- r - 将数据从年度分解为月度
- php - 使用 Symfony 启动服务器时出现 DocumentRoot 错误
- node.js - 无法读取未定义的属性“virtualMachines”
- c - 我无法理解这个#define 语句的用途
- amazon-sagemaker - SageMaker Jupyter(Lab) 中的 VIM(或其他插件)安装
- spring - 在 Spring Boot 多模块项目 fat jar 中未执行 Liquibase 脚本
- python - Keras 在 n 个批次后更新权重
- internet-explorer - 2019 年我还应该支持 Internet Explorer 吗?
- javascript - 如何循环遍历表格并将表单数据动态添加到表格中?