diff --git a/DaoCore/src/main/java/org/greenrobot/greendao/internal/SqlUtils.java b/DaoCore/src/main/java/org/greenrobot/greendao/internal/SqlUtils.java index 1ce0add13..4706f8ffa 100644 --- a/DaoCore/src/main/java/org/greenrobot/greendao/internal/SqlUtils.java +++ b/DaoCore/src/main/java/org/greenrobot/greendao/internal/SqlUtils.java @@ -117,7 +117,14 @@ public static String createSqlSelect(String tablename, String tableAlias, String /** Creates SELECT COUNT(*) with a trailing space. */ public static String createSqlSelectCountStar(String tablename, String tableAliasOrNull) { - StringBuilder builder = new StringBuilder("SELECT COUNT(*) FROM "); + return createSqlSelectCount("*", tablename, tableAliasOrNull); + } + + /** Creates SELECT COUNT($expression) with a trailing space. */ + public static String createSqlSelectCount(String expression, String tablename, String tableAliasOrNull) { + StringBuilder builder = new StringBuilder("SELECT COUNT("); + builder.append(expression); + builder.append(") FROM "); builder.append('"').append(tablename).append('"').append(' '); if (tableAliasOrNull != null) { builder.append(tableAliasOrNull).append(' '); diff --git a/DaoCore/src/main/java/org/greenrobot/greendao/query/QueryBuilder.java b/DaoCore/src/main/java/org/greenrobot/greendao/query/QueryBuilder.java index a27810031..1f43027df 100644 --- a/DaoCore/src/main/java/org/greenrobot/greendao/query/QueryBuilder.java +++ b/DaoCore/src/main/java/org/greenrobot/greendao/query/QueryBuilder.java @@ -276,7 +276,7 @@ public QueryBuilder offset(int offset) { /** * Builds a reusable query object (Query objects can be executed more efficiently than creating a QueryBuilder for - * each execution. + * each execution.) */ public Query build() { StringBuilder builder = createSelectBuilder(); @@ -291,7 +291,7 @@ public Query build() { /** * Builds a reusable query object for low level android.database.Cursor access. - * (Query objects can be executed more efficiently than creating a QueryBuilder for each execution. + * (Query objects can be executed more efficiently than creating a QueryBuilder for each execution.) */ public CursorQuery buildCursor() { StringBuilder builder = createSelectBuilder(); @@ -341,7 +341,7 @@ private int checkAddOffset(StringBuilder builder) { /** * Builds a reusable query object for deletion (Query objects can be executed more efficiently than creating a - * QueryBuilder for each execution. + * QueryBuilder for each execution.) */ public DeleteQuery buildDelete() { if (!joins.isEmpty()) { @@ -366,7 +366,7 @@ public DeleteQuery buildDelete() { /** * Builds a reusable query object for counting rows (Query objects can be executed more efficiently than creating a - * QueryBuilder for each execution. + * QueryBuilder for each execution.) */ public CountQuery buildCount() { String tablename = dao.getTablename(); @@ -380,6 +380,26 @@ public CountQuery buildCount() { return CountQuery.create(dao, sql, values.toArray()); } + /** + * Builds a reusable query object for counting optionally distinct rows according to a column expression. + * (Query objects can be executed more efficiently than creating a QueryBuilder for each execution.) + * + * @param expression column or expression that involves columns to which the COUNT function should be applied + * @param distinct whether the COUNT should be DISTINCT instead of ALL + */ + public CountQuery buildCount(String expression, boolean distinct) { + String tablename = dao.getTablename(); + String optionExpression = distinct ? "DISTINCT " + expression : expression; + String baseSql = SqlUtils.createSqlSelectCount(optionExpression, tablename, tablePrefix); + StringBuilder builder = new StringBuilder(baseSql); + appendJoinsAndWheres(builder, tablePrefix); + + String sql = builder.toString(); + checkLog(sql); + + return CountQuery.create(dao, sql, values.toArray()); + } + private void checkLog(String sql) { if (LOG_SQL) { DaoLog.d("Built SQL for query: " + sql); diff --git a/tests/DaoTest/src/androidTest/java/org/greenrobot/greendao/daotest/query/CountQueryTest.java b/tests/DaoTest/src/androidTest/java/org/greenrobot/greendao/daotest/query/CountQueryTest.java index 17ed7fa77..a73a7ec55 100644 --- a/tests/DaoTest/src/androidTest/java/org/greenrobot/greendao/daotest/query/CountQueryTest.java +++ b/tests/DaoTest/src/androidTest/java/org/greenrobot/greendao/daotest/query/CountQueryTest.java @@ -20,6 +20,7 @@ import java.util.ArrayList; +import org.greenrobot.greendao.daotest.TestEntityDao; import org.greenrobot.greendao.daotest.entity.TestEntityTestBase; import org.greenrobot.greendao.query.CountQuery; import org.greenrobot.greendao.query.Query; @@ -123,4 +124,19 @@ public void testBuildQueryAndCountQuery() { assertEquals(1, countQuery.count()); } + public void testDistinctExpressionCountQuery() { + int value = getSimpleInteger(1); + CountQuery query = dao.queryBuilder().buildCount(Properties.SimpleInteger.columnName, true); + assertEquals(0, query.count()); + + ArrayList inserted = insert(3); + assertEquals(3, query.count()); + + inserted.get(2).setSimpleInteger(value); + dao.update(inserted.get(2)); + assertEquals(2, query.count()); + + dao.deleteAll(); + assertEquals(0, query.count()); + } }