[英]hibernate criteria count over with group by
我有一個帶有user
實體和users
表的 spring 應用程序。 我想獲得按某些字段分組的所有用戶的數量(不是每個組,而是總數)。 在 sql 中它將是:
select
count(*) OVER () as totalRecords
from users u
group by
u.first_name,
u.last_name,
u.age
order by u.age DESC
OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY;
但我真的不能使用休眠標准來做到這一點。 我可以做這樣的事情:
public Long getTotalCount() {
ProjectionList groupBy = projectionList();
groupBy.add(groupProperty("firstName"), "first_name");
groupBy.add(groupProperty("last_name"), "last_name");
groupBy.add(groupProperty("age"), "age");
groupBy.add(Projections.rowCount());
return (Long) getSession().createCriteria("User")
.setProjection(groupBy)
.uniqueResult();
}
但這不是我想要的。 它對每個組進行計數,我想計算group by
子句的結果行
我只是花了幾個小時試圖找出一種方法,並最終讓它發揮作用。
免責聲明
使用普通標准 API 不可能進行最佳查詢。 最佳SELECT COUNT(*) FROM ( group by query here )
是SELECT COUNT(*) FROM ( group by query here )
或SELECT COUNT(*) OVER ()
。 兩者都不可能。 要獲得最佳查詢,請盡可能使用普通 SQL。 對於我的情況,使用純 SQL 是不可能的,因為我構建了一個非常復雜的邏輯來構建標准,並且我想使用相同的邏輯來解決聚合計數(以解決分頁的頁面計數)。
解決方案
首先,我們將以下內容添加到用作標准基礎的所有實體中:
@Entity
class MyEntity {
private Long aggregateRowCount;
@Formula(value="count(*) over()")
public Long getAggregateRowCount() {
return aggregateRowCount;
}
public void setAggregateRowCount(Long aggregateRowCount) {
this.aggregateRowCount = aggregateRowCount;
}
標准構建看起來像這樣:
Criteria criteria = // construct query here
ProjectionList projectionList = // construct Projections.groupProperty list here
projectionList.add(Projections.property("aggregateRowCount")); // this is our custom entity field with the @Formula annotation
criteria.setProjection(projectionList);
criteria.setMaxResults(1);
criteria.setResultTransformer(AggregatedCountResultTransformer.instance());
List<?> res = builder.criteria.list();
if (res.isEmpty()) return 0L;
return (Long) res.get(0);
這將生成如下所示的 SQL:
SELECT groupbyfield1, groupbyfield2, count(*) over()
FROM ...
GROUP BY groupbyfield1, groupbyfield2
LIMIT 1;
如果沒有 LIMIT 1 結果將是
field1 | field2 | count
a | b | 12356
a | c | 12356
... | ... | 12356
但是我們添加了 LIMIT 1( criteria.setMaxResults(1);
),因為第一行已經包含了行數,這就是我們所需要的。
最后,我們的 AggregatedCountResultTransformer:
class AggregatedCountResultTransformer implements ResultTransformer {
private static final AggregatedCountResultTransformer instance = new AggregatedCountResultTransformer();
public static ResultTransformer instance() {
return instance;
}
@Override
public Object transformTuple(Object[] values, String[] fields) {
if (values.length == 0) throw new IllegalStateException("Values is empty");
return values[values.length-1]; // Last value of selected fields (the count)
}
@SuppressWarnings("rawtypes")
@Override
public List transformList(List allResults) {
return allResults; // This is not actually used?
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.