[英]Hibernate Criteria Row Count of Group By Query
我正在尝试使用休眠条件通过查询获取组的结果。 正如您在下面的代码中看到的,我在 ProjectionList 中添加了很多投影。 我在前端有一个分页,所以如果客户端想要获取 20 个结果,我将firstResult
设置为0
并将maxResults
为20
。
我也需要发送此查询的总行数。 但是,如果我使用setProjection(Projections.rowCount)
它将覆盖我的groupby
、 sum
和max
投影。
我怎样才能写出像select count(*) from ( myCriteria )
?
@Override
public SearchResult<ServiceIncomeSO> findServiceIncomesBySearch(IncomeQuery query, Pager pager) {
Criteria criteria = createCriteria(ServiceIncome.class, "sin");
criteria.createAlias("sin.partner", "ptr", JoinType.LEFT_OUTER_JOIN);
if (StringUtils.isNotBlank(query.getPartnerKey())) {
criteria.add(eq("ptr.key", query.getPartnerKey()));
}
if (StringUtils.isNotBlank(query.getPartnerTxt())) {
criteria.add(disjunction() //
.add(ilike("ptr.key", query.getPartnerTxt(), ANYWHERE)) //
.add(ilike("ptr.name", query.getPartnerTxt(), ANYWHERE)) //
.add(ilike("ptr.title", query.getPartnerTxt(), ANYWHERE))); //
}
if (CollectionUtils.isNotEmpty(query.getPartnerTypes())) {
criteria.createAlias("ptr.partnerTypes", "partnerType", JoinType.LEFT_OUTER_JOIN);
criteria.add(in("partnerType." + COLLECTION_ELEMENTS, query.getPartnerTypes()));
}
if (CollectionUtils.isNotEmpty(query.getCategories())) {
criteria.createAlias("ptr.categories", "cat", JoinType.LEFT_OUTER_JOIN);
criteria.add(in("cat.key", query.getCategories()));
}
if (query.getPeriodFromMonth() != null && query.getPeriodFromYear() != null) {
addPeriodFrom(criteria, "sin.year", "sin.month", query.getPeriodFromYear(), query.getPeriodFromMonth());
}
if (query.getPeriodToMonth() != null && query.getPeriodToYear() != null) {
addPeriodTo(criteria, "sin.year", "sin.month", query.getPeriodToYear(), query.getPeriodToMonth());
}
String[] fields;
ProjectionList projection;
if (query.getBreakout() == QueryBreakout.PARTNER) {
projection = Projections.projectionList() //
.add(Projections.groupProperty("sin.partner.key")) //
.add(Projections.groupProperty("sin.year")) //
.add(Projections.groupProperty("sin.month")) //
.add(Projections.sum("sin.subscriberCount")) //
.add(Projections.sum("sin.income"));//
fields = new String[] { "partnerKey", "year", "month", "subscriberCount", "income" };
} else {
projection = Projections.projectionList() //
.add(Projections.groupProperty("sin.partner.key")) //
.add(Projections.groupProperty("sin.service.id")) //
.add(Projections.groupProperty("sin.year")) //
.add(Projections.groupProperty("sin.month")) //
.add(Projections.max("sin.shortNumber")) //
.add(Projections.sum("sin.subscriberCount")) //
.add(Projections.sum("sin.income")) //
; //
fields = new String[] { "partnerKey", "serviceId", "year", "month", "shortNumber", "subscriberCount", "income" };
}
criteria.setProjection(projection);
criteria.addOrder(desc("sin.year")).addOrder(desc("sin.month"));
criteria.setFirstResult(pager.getOffset());
criteria.setMaxResults(pager.getMax());
List<ServiceIncomeSO> list = ((List<Object[]>) criteria.list()).stream() //
.map(values -> JavaLangUtils.setProperties(new ServiceIncomeSO(), fields, values)) //
.collect(Collectors.toList()); //
// TODO How to get count without retrieving all the data?
int totalResults = 0;
return new SearchResult<>(list, totalResults, pager.getMax(), pager.getOffset());
}
private void addPeriodFrom(Criteria criteria, String yearColumn, String periodColumn, int yearFrom, int periodFrom) {
criteria.add(disjunction() // OR
.add(and(eq(yearColumn, yearFrom), ge(periodColumn, periodFrom))) // year == yearFrom && period >= periodFrom
.add(gt(yearColumn, yearFrom))); // year > yearFrom
}
private void addPeriodTo(Criteria criteria, String yearColumn, String periodColumn, int yearFrom, int periodFrom) {
criteria.add(disjunction() // OR
.add(and(eq(yearColumn, yearFrom), le(periodColumn, periodFrom))) // year == yearFrom && period <= periodFrom
.add(lt(yearColumn, yearFrom))); // year < yearFrom
}
我可以用普通 SQL 编写相同的查询,但不能在 Hibernate Criteria API 中执行。
选择查询:
SELECT
PARTNER_KEY,
SERVICE_ID,
INCOME_YEAR,
INCOME_MONTH,
SUM(SUBSCRIBER_COUNT),
SUM(INCOME)
FROM
PP_SERVICE_INCOME
WHERE
PARTNER_KEY = 'PART32143'
GROUP BY
PARTNER_KEY,
SERVICE_ID,
INCOME_YEAR,
INCOME_MONTH;
选择结果:
PARTNER_KEY SERVICE_ID INCOME_YEAR INCOME_MONTH SUM(SUBSCRIBER_COUNT) SUM(INCOME)
----------- ---------- ----------- ------------ --------------------- -----------
PART32143 1 2016 1 1234 175000
PART32143 1 2017 1 1234 175390
PART32143 1 2016 6 1234 151100
PART32143 1 2017 0 1234 157800
PART32143 1 2016 7 1234 175220
PART32143 1 2016 2 1234 143000
PART32143 1 2016 0 1234 150000
PART32143 1 2017 2 1234 143012
PART32143 1 2016 8 1234 143330
计数查询:
SELECT
COUNT(*)
FROM (
SELECT
PARTNER_KEY,
SERVICE_ID,
INCOME_YEAR,
INCOME_MONTH,
SUM(SUBSCRIBER_COUNT),
SUM(INCOME)
FROM
PP_SERVICE_INCOME
WHERE
PARTNER_KEY = 'PART32143'
GROUP BY
PARTNER_KEY,
SERVICE_ID,
INCOME_YEAR,
INCOME_MONTH
);
计数结果:9
为此,首先您像这样使用DetachedCriteria
进行group by
,
DetachedCriteria dcrit = DetachedCriteria.forClass(Student.class);
dcrit.setProjection(Projections.projectionList()
.add(Projections.groupProperty("studentname").as("name")));
分组后,通过添加DetachedCriteria
作为Criteria
的子查询,使用条件获取行数,如下所示,
Criteria crit = sessionFactory.getCurrentSession().createCriteria(Student.class);
crit.add(Subqueries.propertyIn("id", dcrit));
crit.setProjection( Projections.rowCount() );
return ((Number) crit.uniqueResult()).intValue();
您首先要做的不是为ServiceIncome
内部查询创建Criteria
,而是希望将其创建为DetachedCriteria
,如下所示:
DetachedCriteria myCriteria = DetachedCriteria.forClass(
ServiceIncome.class,
"sin"
);
然后,您想像通常使用Session
一样创建外部条件,然后将子查询指定为我们在上面指定的DetachedCriteria
和所需的投影。
Criteria outerCriteria = session.createCriteria( ServiceIncome.class, "osin" );
outerCriteria.add( Subqueries.propertyIn( "id", myCriteria ) );
outerCriteria.setProjection( Projections.rowCount );
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.