聚合子查询结果的 JPA 聚合
JPA aggregation on aggregated subquery result
我有以下 JPA 实体(吸气剂,setter 和省略的非相关字段):
@Entity
@Table(name = "transaction")
public class Transaction {
@Id
@GeneratedValue
@Column(name = "id")
private Long id;
@Column(name = "start_date", nullable = false)
private Date startDate;
}
我的目标是使用 JPQL 或条件 API 实现查询,这将 return 每天的平均交易量和每天的最大交易量。
本机 SQL 查询(MySQL 数据库)给出所需的结果如下所示:
select max(cnt) from (
select date(start_date) start_date, count(t.id) cnt
from transaction t
group by date(t.start_date)
) t;
select avg(cnt) from (
select date(start_date) start_date, count(t.id) cnt
from transaction t
group by date(t.start_date)
) t;
不幸的是,不鼓励使用本机 SQL 查询,并且 JPQL 不允许在 where 子句中使用子查询。
提前致谢。
加法:
我从以下Spring数据查询开始:
@Query("select max(cnt) from ("
+ "select date(t.startDate) startDate, count(t.id) cnt "
+ "from Transaction t "
+ "group by date(t.startDate))")
但显然没有成功:
org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: ( near line 1, column 22 [select max(cnt) from (select date(t.startDate) startDate, count(t.id) cnt from Transaction t group by date(startDate))]
我可以想象,使用排序和限制输出可以管理 max 的搜索,但这对 avg 没有帮助。
有两个原因导致无法在 JPQL(或 Criteria)中编写您想要的内容:
- FROM中的子查询,如你所指
- 日期函数 - MySQL/Hibernate 具体。
对于此查询,您可能只询问可移植性(尽可能保持原生 SQL 标准)。
一种选择是使用 FluentJPA,它消除了嵌入式字符串并与 Java 和 JPA 紧密集成。所以查询将如下所示:
public int getAvgCount() {
FluentQuery query = FluentJPA.SQL(() -> {
DailyCount daily = subQuery((Transaction t) -> {
Date date = alias(DATE(t.getStartDate()), DailyCount::getDate);
int count = alias(COUNT(t.getId()), DailyCount::getCount);
SELECT(date, count);
FROM(t);
GROUP(BY(date));
});
SELECT(AVG(daily.getCount())); // or MAX
FROM(daily);
});
return query.createQuery(em, Integer.class).getSingleResult();
}
类型声明:
@Tuple
@Getter // lombok
public class DailyCount {
private Integer count;
private Date date;
}
结果SQL:
SELECT AVG(q0.count)
FROM (SELECT DATE(t0.start_date) AS date, COUNT(t0.id) AS count
FROM transaction t0
GROUP BY DATE(t0.start_date)) q0
我有以下 JPA 实体(吸气剂,setter 和省略的非相关字段):
@Entity
@Table(name = "transaction")
public class Transaction {
@Id
@GeneratedValue
@Column(name = "id")
private Long id;
@Column(name = "start_date", nullable = false)
private Date startDate;
}
我的目标是使用 JPQL 或条件 API 实现查询,这将 return 每天的平均交易量和每天的最大交易量。
本机 SQL 查询(MySQL 数据库)给出所需的结果如下所示:
select max(cnt) from (
select date(start_date) start_date, count(t.id) cnt
from transaction t
group by date(t.start_date)
) t;
select avg(cnt) from (
select date(start_date) start_date, count(t.id) cnt
from transaction t
group by date(t.start_date)
) t;
不幸的是,不鼓励使用本机 SQL 查询,并且 JPQL 不允许在 where 子句中使用子查询。
提前致谢。
加法:
我从以下Spring数据查询开始:
@Query("select max(cnt) from ("
+ "select date(t.startDate) startDate, count(t.id) cnt "
+ "from Transaction t "
+ "group by date(t.startDate))")
但显然没有成功:
org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: ( near line 1, column 22 [select max(cnt) from (select date(t.startDate) startDate, count(t.id) cnt from Transaction t group by date(startDate))]
我可以想象,使用排序和限制输出可以管理 max 的搜索,但这对 avg 没有帮助。
有两个原因导致无法在 JPQL(或 Criteria)中编写您想要的内容:
- FROM中的子查询,如你所指
- 日期函数 - MySQL/Hibernate 具体。
对于此查询,您可能只询问可移植性(尽可能保持原生 SQL 标准)。
一种选择是使用 FluentJPA,它消除了嵌入式字符串并与 Java 和 JPA 紧密集成。所以查询将如下所示:
public int getAvgCount() {
FluentQuery query = FluentJPA.SQL(() -> {
DailyCount daily = subQuery((Transaction t) -> {
Date date = alias(DATE(t.getStartDate()), DailyCount::getDate);
int count = alias(COUNT(t.getId()), DailyCount::getCount);
SELECT(date, count);
FROM(t);
GROUP(BY(date));
});
SELECT(AVG(daily.getCount())); // or MAX
FROM(daily);
});
return query.createQuery(em, Integer.class).getSingleResult();
}
类型声明:
@Tuple
@Getter // lombok
public class DailyCount {
private Integer count;
private Date date;
}
结果SQL:
SELECT AVG(q0.count)
FROM (SELECT DATE(t0.start_date) AS date, COUNT(t0.id) AS count
FROM transaction t0
GROUP BY DATE(t0.start_date)) q0