2017-02-26 47 views
0

我試圖通過帶有休眠標準的查詢來獲取組的結果。正如你在下面的代碼中看到的那樣,我在ProjectionList中添加了很多投影。我在前端分頁,所以如果客戶想要獲取20個結果,我將firstResult設置爲0maxResults20休眠條件按查詢分組的行數

我也需要發送此查詢的總行數。但是,如果我使用setProjection(Projections.rowCount)它將覆蓋我的groupbysummax預測。

我該怎麼寫類似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

回答

0

你首先想要做的是什麼,而不是創造一個CriteriaServiceIncome內部查詢,要創建爲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); 
+0

首先,分組查詢不會產生「id」列表。另外,我想要計算的不是數據庫中的行,而是它通過表達式返回的行數。例如,10個ServiceIncome對象可能具有相同的partnerKey,year和month。因此,它們將被分組成一行。在這種情況下,計數查詢必須返回1。 – sedran