[#2200] Add Executor.fetchCount(Select<?>) and Select.fetchCount() to

replace the projection by a COUNT(*) query
This commit is contained in:
Lukas Eder 2013-02-19 11:01:47 +01:00
parent 1959ee6411
commit bbd774795c
6 changed files with 89 additions and 0 deletions

View File

@ -59,6 +59,7 @@ import static org.jooq.impl.Factory.cumeDist;
import static org.jooq.impl.Factory.denseRank;
import static org.jooq.impl.Factory.firstValue;
import static org.jooq.impl.Factory.groupConcat;
import static org.jooq.impl.Factory.inline;
import static org.jooq.impl.Factory.lag;
import static org.jooq.impl.Factory.lead;
import static org.jooq.impl.Factory.listAgg;
@ -68,6 +69,7 @@ import static org.jooq.impl.Factory.median;
import static org.jooq.impl.Factory.min;
import static org.jooq.impl.Factory.minDistinct;
import static org.jooq.impl.Factory.ntile;
import static org.jooq.impl.Factory.one;
import static org.jooq.impl.Factory.percentRank;
import static org.jooq.impl.Factory.rank;
import static org.jooq.impl.Factory.regrAvgX;
@ -80,6 +82,9 @@ import static org.jooq.impl.Factory.regrSXY;
import static org.jooq.impl.Factory.regrSYY;
import static org.jooq.impl.Factory.regrSlope;
import static org.jooq.impl.Factory.rowNumber;
import static org.jooq.impl.Factory.select;
import static org.jooq.impl.Factory.selectDistinct;
import static org.jooq.impl.Factory.selectFrom;
import static org.jooq.impl.Factory.stddevPop;
import static org.jooq.impl.Factory.stddevSamp;
import static org.jooq.impl.Factory.sum;
@ -280,6 +285,23 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
assertEquals(4, (int) result3.get(1).getValue(2, Integer.class));
}
@Test
public void testFetchCount() throws Exception {
assertEquals(1, create().fetchCount(select(one().as("x"))));
assertEquals(1, create().select(one().as("x")).fetchCount());
assertEquals(4, create().fetchCount(select(TBook_ID(), TBook_TITLE()).from(TBook())));
assertEquals(4, create().select(TBook_ID(), TBook_TITLE()).from(TBook()).fetchCount());
assertEquals(3, create().fetchCount(selectDistinct(TBook_ID(), TBook_TITLE()).from(TBook()).where(TBook_ID().in(1, 2, 3))));
assertEquals(2, create().fetchCount(selectFrom(TBook()).limit(2)));
assertEquals(2, create().fetchCount(selectFrom(TBook()).limit(2).offset(1)));
assertEquals(2, create().fetchCount(
select(TBook_TITLE()).from(TBook()).where(TBook_ID().eq(1))
.union(
select(inline("abc")))));
}
@Test
public void testCountDistinct() throws Exception {

View File

@ -1717,6 +1717,11 @@ public abstract class jOOQAbstractTest<
new AggregateWindowFunctionTests(this).testAggregateFunctions();
}
@Test
public void testFetchCount() throws Exception {
new AggregateWindowFunctionTests(this).testFetchCount();
}
@Test
public void testCountDistinct() throws Exception {
new AggregateWindowFunctionTests(this).testCountDistinct();

View File

@ -37,6 +37,8 @@ package org.jooq;
import java.util.List;
import org.jooq.exception.DataAccessException;
/**
* A {@link Query} that can provide a {@link Result} after execution
*
@ -73,4 +75,27 @@ public interface Select<R extends Record> extends ResultQuery<R>, TableLike<R>,
* All fields selected in this query
*/
List<Field<?>> getSelect();
/**
* Execute this query in the context of its attached executor and return
* a <code>COUNT(*)</code> value.
* <p>
* This wraps a pre-existing <code>SELECT</code> query in another one to
* calculate the <code>COUNT(*)</code> value, without modifying the original
* <code>SELECT</code>. An example: <code><pre>
* -- Original query:
* SELECT id, title FROM book WHERE title LIKE '%a%'
*
* -- Wrapped query:
* SELECT count(*) FROM (
* SELECT id, title FROM book WHERE title LIKE '%a%'
* )
* </pre></code> This is particularly useful for those databases that do not
* support the <code>COUNT(*) OVER()</code> window function to calculate
* total results in paged queries.
*
* @return The <code>COUNT(*)</code> result
* @throws DataAccessException if something went wrong executing the query
*/
int fetchCount() throws DataAccessException;
}

View File

@ -48,6 +48,7 @@ import org.jooq.Result;
import org.jooq.Row;
import org.jooq.Select;
import org.jooq.Table;
import org.jooq.exception.DataAccessException;
/**
* A common base class for all <code>SELECT</code> statements.
@ -62,6 +63,11 @@ abstract class AbstractSelect<R extends Record> extends AbstractResultQuery<R> i
super(configuration);
}
@Override
public final int fetchCount() throws DataAccessException {
return new Executor(getConfiguration()).fetchCount(this);
}
@Override
public final Select<R> union(Select<? extends R> select) {
return new Union<R>(getConfiguration(), this, select, CombineOperator.UNION);

View File

@ -5328,6 +5328,32 @@ public class Executor implements Configuration {
}
}
/**
* Execute a {@link Select} query in the context of this executor and return
* a <code>COUNT(*)</code> value.
* <p>
* This wraps a pre-existing <code>SELECT</code> query in another one to
* calculate the <code>COUNT(*)</code> value, without modifying the original
* <code>SELECT</code>. An example: <code><pre>
* -- Original query:
* SELECT id, title FROM book WHERE title LIKE '%a%'
*
* -- Wrapped query:
* SELECT count(*) FROM (
* SELECT id, title FROM book WHERE title LIKE '%a%'
* )
* </pre></code> This is particularly useful for those databases that do not
* support the <code>COUNT(*) OVER()</code> window function to calculate
* total results in paged queries.
*
* @param query The wrapped query
* @return The <code>COUNT(*)</code> result
* @throws DataAccessException if something went wrong executing the query
*/
public final int fetchCount(Select<?> query) throws DataAccessException {
return selectCount().from(query).fetchOne(0, int.class);
}
/**
* Execute a {@link Query} in the context of this executor.
*

View File

@ -153,6 +153,11 @@ class SelectImpl<R extends Record> extends AbstractDelegatingQuery<Select<R>> im
return (SelectQuery<R>) getDelegate();
}
@Override
public final int fetchCount() {
return getDelegate().fetchCount();
}
/**
* This method must be able to return both incompatible types
* SelectSelectStep&lt;Record> and SelectSelectStep&lt;R>