我需要在下面生成预期结果。基本上,它是根据特定时间段(每周,每月等)聚合值的查询。有一个日期过滤器,有开始和结束,我们需要返回所有范围的值。如果它们不存在,则应返回0.
在下面的示例中,开始日期为“2015-08-02”,日期为“2015-08-23”,期间为每周。请注意,对于第2周,我们没有值,但应该返回零值。
那么,在这种情况下,使用JPA执行此操作的最佳方法是什么?我们考虑使用临时表并将结果与此表连接以获得整个范围的结果,但我不知道是否可以使用JPA,因为我们需要创建表,连接然后销毁临时表。 / p>
另一种选择是创建数据库视图并将其映射到实体。
在上面的例子中,JPQL查询应该是这样的:
@Query("select status, sum(totalInvoice), week from Invoice where " +
"left join TempTable as tt..." + <-- TEMP TABLE OR VIEW TO GET THE PERIODS
"issuer.id = :issuerId and type = :type and (:recipientId is null or recipient.id = :recipientId) and " +
"status in ('ISSUED', 'PAID') " +
"group by status")
另一种选择是使用存储过程,但它们似乎很难用JPA实现,我认为它们不是必需的。
预期结果:
{
"code":"xxx",
"title":"This is the title of the first series"
"type":"PERIODIC",
"period":"WEEKLY", <-- PERIOD
"from":"2015-08-02",
"to":"2015-08-29",
"labels": ["2015-08-02", "2015-08-09", "2015-08-16", "2015-08-23"],
"tabelType": "TEXT",
"series":[
{
"code":"xxx",
"title":"This is the title of the first series"
"values":[10, 0, 13, 18] <- in this example, we don't have values for label "2015-08-09"
},
{
"code":"xxx",
"title":"This is the title of the second series"
"values":[10, 0, 13, 18] <- in this example, we don't have values for label "2015-08-09"
}
]
}
答案 0 :(得分:2)
@pozs在这里提供了答案。这只能通过本机查询(PostgreSQL)来完成。结果如下:
/**
* Returns the counts, totals and averages of the states by their currency, period and status.
*/
@Query(value = "select i.currency, date(p), i.status, count(id), sum(coalesce(i.total, 0)), avg(coalesce(i.total, 0)) " +
"from generate_series(date_trunc(:period, cast(:from as timestamp)), date_trunc(:period, cast(:to as timestamp)) + cast('1 ' || :period as interval), cast('1 ' || :period as interval)) p " +
"inner join invoice i on i.due_date >= p and i.due_date < p + cast('1 ' || :period as interval) " +
"where issuer_id = :issuerId and type = :type and (:recipientId = 0 or recipient_id = :recipientId) and type = :type " +
"group by i.currency, date(p), i.status " +
"order by i.currency, date(p), i.status", nativeQuery = true)
List<Object[]> getIssuerStatementTotalsByCurrencyPeriodAndStatus(
@Param("issuerId") long issuerId,
@Param("recipientId") long recipientId,
@Param("type") String statementType,
@Param("from") String from,
@Param("to") String to,
@Param("period") String period);
请注意,这将返回Object数组的列表。另请注意,我无法将枚举和复杂参数传递给方法。我不得不将这些值贬低为字符串和原语。
我已将此结果转化为具有以下类别的有意义的内容:
/**
* Contains the result of a single result in an aggregate query.
*/
public class AggregateResult {
private List<String> keys;
private List<BigDecimal> values;
@SuppressWarnings("unused")
public AggregateResult(Object value1, Object value2) {
this(new Object[] { value1, value2 });
}
@SuppressWarnings("unused")
public AggregateResult(Object value1, Object value2, Object value3) {
this(new Object[] { value1, value2, value3 });
}
@SuppressWarnings("unused")
public AggregateResult(Object value1, Object value2, Object value3, Object value4) {
this(new Object[] { value1, value2, value3, value4 });
}
@SuppressWarnings("unused")
public AggregateResult(Object value1, Object value2, Object value3, Object value4, Object value5) {
this(new Object[] { value1, value2, value3, value4, value5 });
}
public AggregateResult(Object... vals) {
values = new ArrayList<>();
while (values.size() < vals.length && vals[vals.length - values.size() - 1] instanceof Number) {
Number number = (Number) vals[vals.length - values.size() - 1];
values.add(number instanceof BigDecimal ? (BigDecimal) number : new BigDecimal(number.toString()));
}
this.keys = Stream.of(ArrayUtils.subarray(vals, 0, vals.length - values.size())).map(Object::toString).collect(toList());
}
public List<String> getKeys() {
return keys;
}
public List<BigDecimal> getValues() {
return values;
}
/**
* Returns the list of {@link AggregateResult}s for the raw result. The raw result is expected to
* have been returned from a native JPA query.
*/
public static List<AggregateResult> fromNativeResult(List<Object[]> raw) {
return raw.stream().map(AggregateResult::new).collect(toList());
}
}
答案 1 :(得分:1)
这可能不是您问题的直接答案,但是:为什么需要直接在JPA查询中进行分组而不是Java代码?这种类型的复杂语义分组是使用Java完美完成的,但SQL数据库通常不太擅长生成这种类型的结构化数据。如果没有其他原因在数据库级别上执行此操作(例如,您需要一个填充了此数据的视图,该视图可根据句点进行搜索),那么只需加载原始数据并使用Java代码填充结构 - 它将少得多编码开销也可能更高效。