簡體   English   中英

休眠條件計數與分組依據

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM