[jOOQ/jOOQ#11670] Add support for GROUP BY DISTINCT

This commit is contained in:
Lukas Eder 2021-10-26 12:37:12 +02:00
parent 1fe17ecbaa
commit c81cf7bd59
7 changed files with 86 additions and 7 deletions

View File

@ -192,6 +192,7 @@ public interface Select<R extends Record> extends ResultQuery<R>, TableLike<R>,
@NotNull Select<?> $from(MList<? extends Table<?>> from);
@Nullable Condition $where();
@NotNull MList<? extends GroupField> $groupBy();
boolean $groupByDistinct();
@Nullable Condition $having();
@NotNull MList<? extends WindowDefinition> $window();
@Nullable Condition $qualify();

View File

@ -37,8 +37,11 @@
*/
package org.jooq;
import org.jooq.impl.DSL;
import org.jetbrains.annotations.*;
import static org.jooq.SQLDialect.POSTGRES;
import java.util.Collection;
@ -123,4 +126,26 @@ public interface SelectGroupByStep<R extends Record> extends SelectHavingStep<R>
@NotNull @CheckReturnValue
@Support
SelectHavingStep<R> groupBy(Collection<? extends GroupField> fields);
/**
* Add a <code>GROUP BY DISTINCT</code> clause to the query
* <p>
* This is mostly useful when combined with
* {@link DSL#groupingSets(Field[]...)} to remove duplicate grouping set
* results prior to aggregation and projection.
*/
@NotNull @CheckReturnValue
@Support({ POSTGRES })
SelectHavingStep<R> groupByDistinct(GroupField... fields);
/**
* Add a <code>GROUP BY DISTINCT</code> clause to the query
* <p>
* This is mostly useful when combined with
* {@link DSL#groupingSets(Field[]...)} to remove duplicate grouping set
* results prior to aggregation and projection.
*/
@NotNull @CheckReturnValue
@Support({ POSTGRES })
SelectHavingStep<R> groupByDistinct(Collection<? extends GroupField> fields);
}

View File

@ -71,6 +71,7 @@ import static org.jooq.SQLDialect.POSTGRES;
// ...
// ...
// ...
// ...
import static org.jooq.SQLDialect.SQLITE;
// ...
// ...
@ -341,6 +342,16 @@ public interface SelectQuery<R extends Record> extends Select<R>, ConditionProvi
@Support
void addGroupBy(Collection<? extends GroupField> fields);
/**
* Specifies the <code>GROUP BY DISTINCT</code> clause.
* <p>
* This is mostly useful when combined with
* {@link DSL#groupingSets(Field[]...)} to remove duplicate grouping set
* results prior to aggregation and projection.
*/
@Support({ POSTGRES })
void setGroupByDistinct(boolean groupByDistinct);
/**
* Adds a new condition to the having clause of the query, connecting it
* with each other with {@link Operator#AND}.

View File

@ -43,6 +43,7 @@ package org.jooq.impl;
import static org.jooq.SQLDialect.POSTGRES;
// ...
// ...
// ...
import static org.jooq.impl.Keywords.K_IN;
import static org.jooq.impl.Keywords.K_INOUT;
import static org.jooq.impl.Keywords.K_OUT;

View File

@ -1775,6 +1775,9 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
List<GroupField> groupBy;
if (parseKeywordIf("GROUP BY")) {
if (!parseKeywordIf("ALL") && parseKeywordIf("DISTINCT"))
result.setGroupByDistinct(true);
if (parseIf('(')) {
parse(')');
result.addGroupBy();

View File

@ -702,6 +702,20 @@ implements
return this;
}
@Override
public final SelectImpl groupByDistinct(GroupField... fields) {
getQuery().addGroupBy(fields);
getQuery().setGroupByDistinct(true);
return this;
}
@Override
public final SelectImpl groupByDistinct(Collection<? extends GroupField> fields) {
getQuery().addGroupBy(fields);
getQuery().setGroupByDistinct(true);
return this;
}
@Override
@ -3395,6 +3409,11 @@ implements
return getDelegate().$groupBy();
}
@Override
public final boolean $groupByDistinct() {
return getDelegate().$groupByDistinct();
}
@Override
public final Condition $having() {
return getDelegate().$having();

View File

@ -389,6 +389,7 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
private final ConditionProviderImpl condition;
private boolean grouping;
private QueryPartList<GroupField> groupBy;
private boolean groupByDistinct;
private final ConditionProviderImpl having;
private WindowList window;
private final ConditionProviderImpl qualify;
@ -524,6 +525,7 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
private final SelectQueryImpl<R> copyTo(CopyClause clause, boolean scalarSelect, SelectQueryImpl<R> result) {
@ -552,6 +554,7 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
result.grouping = grouping;
result.groupBy = groupBy;
result.groupByDistinct = groupByDistinct;
result.having.setWhere(having.getWhere());
if (window != null)
result.addWindow(window);
@ -2402,8 +2405,12 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
if (grouping) {
context.formatSeparator()
.visit(K_GROUP_BY)
.separatorRequired(true);
.visit(K_GROUP_BY);
if (groupByDistinct)
context.sql(' ').visit(K_DISTINCT);
context.separatorRequired(true);
// [#1665] Empty GROUP BY () clauses need parentheses
if (Tools.isEmpty(groupBy)) {
@ -3854,6 +3861,9 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
final void setGrouping() {
grouping = true;
if (groupBy == null)
groupBy = new QueryPartList<>();
}
final ConditionProviderImpl getWhere(Context<?> ctx) {
@ -4149,13 +4159,15 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
@Override
public final void addGroupBy(Collection<? extends GroupField> fields) {
setGrouping();
if (groupBy == null)
groupBy = new QueryPartList<>();
groupBy.addAll(fields);
}
@Override
public final void setGroupByDistinct(boolean groupByDistinct) {
setGrouping();
this.groupByDistinct = groupByDistinct;
}
@Override
public final void addGroupBy(GroupField... fields) {
addGroupBy(Arrays.asList(fields));
@ -4543,6 +4555,11 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
return groupBy == null ? QueryPartList.emptyList() : groupBy;
}
@Override
public final boolean $groupByDistinct() {
return groupByDistinct;
}
@Override
public final Condition $having() {
return having;
@ -4594,16 +4611,18 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
$from(),
$where(),
$groupBy(),
$groupByDistinct(),
$having(),
$window(),
$qualify(),
$orderBy(),
(cte, s, d, f, c, g, h, w, q, o) -> {
(cte, s, d, f, c, g, gd, h, w, q, o) -> {
SelectQueryImpl<?> r = new SelectQueryImpl<>(configuration(), cte, d);
r.select.addAll(s);
r.from.addAll(f);
r.condition.addConditions(extractCondition(c));
r.groupBy = g;
r.groupByDistinct = gd;
r.having.addConditions(extractCondition(h));
r.addWindow(w);
r.qualify.addConditions(extractCondition(q));