mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
NEW: FetchCountDistinct - query can return distinct values with their counts (#1300)
* NEW: FetchCountDistinct - query can return distinct values with their counts * Have to disable asserts, because of #1298
This commit is contained in:
committed by
Rob Bygrave
parent
021d57f4b2
commit
c1b022c123
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.query;
|
||||
|
||||
import io.ebean.CountDistinctOrder;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.RawSql;
|
||||
import io.ebean.RawSqlBuilder;
|
||||
@@ -190,7 +191,7 @@ class CQueryBuilder {
|
||||
CQueryPlan queryPlan = request.getQueryPlan();
|
||||
if (queryPlan != null) {
|
||||
predicates.prepare(false);
|
||||
return new CQueryFetchSingleAttribute(request, predicates, queryPlan);
|
||||
return new CQueryFetchSingleAttribute(request, predicates, queryPlan, query.isCountDistinct());
|
||||
}
|
||||
|
||||
// use RawSql or generated Sql
|
||||
@@ -201,7 +202,7 @@ class CQueryBuilder {
|
||||
|
||||
queryPlan = new CQueryPlan(request, s.getSql(), sqlTree, false, s.isIncludesRowNumberColumn(), predicates.getLogWhereSql());
|
||||
request.putQueryPlan(queryPlan);
|
||||
return new CQueryFetchSingleAttribute(request, predicates, queryPlan);
|
||||
return new CQueryFetchSingleAttribute(request, predicates, queryPlan, query.isCountDistinct());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -549,8 +550,13 @@ class CQueryBuilder {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sb.append(select.getSelectSql());
|
||||
if (query.isCountDistinct() && query.isSingleAttribute()) {
|
||||
sb.append("r1.attribute_, count(*) from (select ");
|
||||
sb.append(select.getSelectSql());
|
||||
sb.append(" as attribute_");
|
||||
} else {
|
||||
sb.append(select.getSelectSql());
|
||||
}
|
||||
if (query.isDistinctQuery() && dbOrderBy != null && !query.isSingleAttribute()) {
|
||||
// add the orderBy columns to the select clause (due to distinct)
|
||||
sb.append(", ").append(DbOrderByTrim.trim(dbOrderBy));
|
||||
@@ -642,10 +648,15 @@ class CQueryBuilder {
|
||||
sb.append(" having ").append(dbHaving);
|
||||
}
|
||||
|
||||
if (dbOrderBy != null) {
|
||||
if (dbOrderBy != null && !query.isCountDistinct()) {
|
||||
sb.append(" order by ").append(dbOrderBy);
|
||||
}
|
||||
|
||||
if (query.isCountDistinct() && query.isSingleAttribute()) {
|
||||
sb.append(") r1 group by r1.attribute_");
|
||||
sb.append(toSql(query.getCountDistinctOrder()));
|
||||
}
|
||||
|
||||
if (useSqlLimiter) {
|
||||
// use LIMIT/OFFSET, ROW_NUMBER() or rownum type SQL query limitation
|
||||
SqlLimitRequest r = new OrmQueryLimitRequest(sb.toString(), dbOrderBy, query, dbPlatform);
|
||||
@@ -657,6 +668,25 @@ class CQueryBuilder {
|
||||
|
||||
}
|
||||
|
||||
private String toSql(CountDistinctOrder orderBy) {
|
||||
switch(orderBy) {
|
||||
case ATTR_ASC:
|
||||
return " order by r1.attribute_";
|
||||
case ATTR_DESC:
|
||||
return " order by r1.attribute_ desc";
|
||||
case COUNT_ASC_ATTR_ASC:
|
||||
return " order by count(*), r1.attribute_";
|
||||
case COUNT_ASC_ATTR_DESC:
|
||||
return " order by count(*), r1.attribute_ desc";
|
||||
case COUNT_DESC_ATTR_ASC:
|
||||
return " order by count(*) desc, r1.attribute_";
|
||||
case COUNT_DESC_ATTR_DESC:
|
||||
return " order by count(*) desc, r1.attribute_ desc";
|
||||
default:
|
||||
throw new IllegalArgumentException("Illegal enum: "+ orderBy);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Append where or and based on the hasWhere flag.
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.server.query;
|
||||
|
||||
import io.ebean.util.JdbcClose;
|
||||
import io.ebean.CountedValue;
|
||||
import io.ebeaninternal.api.SpiProfileTransactionEvent;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.api.SpiTransaction;
|
||||
@@ -60,18 +61,21 @@ class CQueryFetchSingleAttribute implements SpiProfileTransactionEvent {
|
||||
|
||||
private final ScalarType<?> scalarType;
|
||||
|
||||
private final boolean containsCounts;
|
||||
|
||||
private long profileOffset;
|
||||
|
||||
/**
|
||||
* Create the Sql select based on the request.
|
||||
*/
|
||||
CQueryFetchSingleAttribute(OrmQueryRequest<?> request, CQueryPredicates predicates, CQueryPlan queryPlan) {
|
||||
CQueryFetchSingleAttribute(OrmQueryRequest<?> request, CQueryPredicates predicates, CQueryPlan queryPlan, boolean containsCounts) {
|
||||
this.request = request;
|
||||
this.queryPlan = queryPlan;
|
||||
this.query = request.getQuery();
|
||||
this.sql = queryPlan.getSql();
|
||||
this.desc = request.getBeanDescriptor();
|
||||
this.predicates = predicates;
|
||||
this.containsCounts = containsCounts;
|
||||
this.scalarType = queryPlan.getSingleAttributeScalarType();
|
||||
query.setGeneratedSql(sql);
|
||||
}
|
||||
@@ -101,7 +105,11 @@ class CQueryFetchSingleAttribute implements SpiProfileTransactionEvent {
|
||||
|
||||
List<Object> result = new ArrayList<>();
|
||||
while (dataReader.next()) {
|
||||
result.add(scalarType.read(dataReader));
|
||||
Object value = scalarType.read(dataReader);
|
||||
if (containsCounts) {
|
||||
value = new CountedValue<>(value, dataReader.getLong());
|
||||
}
|
||||
result.add(value);
|
||||
dataReader.resetColumnPosition();
|
||||
rowCount++;
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ public final class SqlTreeBuilder {
|
||||
this.query = request.getQuery();
|
||||
this.temporalMode = SpiQuery.TemporalMode.of(query);
|
||||
this.disableLazyLoad = query.isDisableLazyLoading();
|
||||
this.subQuery = Type.SUBQUERY == query.getType() || Type.ID_LIST == query.getType();
|
||||
this.subQuery = Type.SUBQUERY == query.getType() || Type.ID_LIST == query.getType() || Type.DELETE == query.getType() || query.isCountDistinct();
|
||||
this.includeJoin = query.getM2mIncludeJoin();
|
||||
this.manyWhereJoins = query.getManyWhereJoins();
|
||||
this.queryDetail = query.getDetail();
|
||||
|
||||
Reference in New Issue
Block a user