SQL: Remove restriction for single column grouping (#31818)
For historical reasons SQL restricts GROUP BY to only one field. This commit removes the restriction and improves the test suite with multi group by tests. Close #31793
This commit is contained in:
parent
994a251075
commit
9ffb26ab02
|
@ -177,6 +177,13 @@ And grouping by column expression (typically used along-side an alias):
|
|||
include-tagged::{sql-specs}/docs.csv-spec[groupByExpression]
|
||||
----
|
||||
|
||||
Or a mixture of the above:
|
||||
["source","sql",subs="attributes,callouts,macros"]
|
||||
----
|
||||
include-tagged::{sql-specs}/docs.csv-spec[groupByMulti]
|
||||
----
|
||||
|
||||
|
||||
When a `GROUP BY` clause is used in a `SELECT`, _all_ output expressions must be either aggregate functions or expressions used for grouping or derivatives of (otherwise there would be more than one possible value to return for each ungrouped column).
|
||||
|
||||
To wit:
|
||||
|
|
|
@ -104,6 +104,14 @@ public abstract class Expressions {
|
|||
return null;
|
||||
}
|
||||
|
||||
public static boolean equalsAsAttribute(Expression left, Expression right) {
|
||||
if (!left.semanticEquals(right)) {
|
||||
Attribute l = attribute(left);
|
||||
return (l != null && l.semanticEquals(attribute(right)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static TypeResolution typeMustBe(Expression e, Predicate<Expression> predicate, String message) {
|
||||
return predicate.test(e) ? TypeResolution.TYPE_RESOLVED : new TypeResolution(message);
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ public class Optimizer extends RuleExecutor<LogicalPlan> {
|
|||
new ReplaceAggsWithStats(),
|
||||
new PromoteStatsToExtendedStats(),
|
||||
new ReplaceAggsWithPercentiles(),
|
||||
new ReplceAggsWithPercentileRanks()
|
||||
new ReplaceAggsWithPercentileRanks()
|
||||
);
|
||||
|
||||
Batch operators = new Batch("Operator Optimization",
|
||||
|
@ -132,7 +132,9 @@ public class Optimizer extends RuleExecutor<LogicalPlan> {
|
|||
new PruneFilters(),
|
||||
new PruneOrderBy(),
|
||||
new PruneOrderByNestedFields(),
|
||||
new PruneCast()
|
||||
new PruneCast(),
|
||||
// order by alignment of the aggs
|
||||
new SortAggregateOnOrderBy()
|
||||
// requires changes in the folding
|
||||
// since the exact same function, with the same ID can appear in multiple places
|
||||
// see https://github.com/elastic/x-pack-elasticsearch/issues/3527
|
||||
|
@ -612,7 +614,7 @@ public class Optimizer extends RuleExecutor<LogicalPlan> {
|
|||
}
|
||||
}
|
||||
|
||||
static class ReplceAggsWithPercentileRanks extends Rule<LogicalPlan, LogicalPlan> {
|
||||
static class ReplaceAggsWithPercentileRanks extends Rule<LogicalPlan, LogicalPlan> {
|
||||
|
||||
@Override
|
||||
public LogicalPlan apply(LogicalPlan p) {
|
||||
|
@ -828,6 +830,46 @@ public class Optimizer extends RuleExecutor<LogicalPlan> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Align the order in aggregate based on the order by.
|
||||
*/
|
||||
static class SortAggregateOnOrderBy extends OptimizerRule<OrderBy> {
|
||||
|
||||
@Override
|
||||
protected LogicalPlan rule(OrderBy ob) {
|
||||
List<Order> order = ob.order();
|
||||
|
||||
// remove constants
|
||||
List<Order> nonConstant = order.stream().filter(o -> !o.child().foldable()).collect(toList());
|
||||
|
||||
// if the sort points to an agg, change the agg order based on the order
|
||||
if (ob.child() instanceof Aggregate) {
|
||||
Aggregate a = (Aggregate) ob.child();
|
||||
List<Expression> groupings = new ArrayList<>(a.groupings());
|
||||
boolean orderChanged = false;
|
||||
|
||||
for (int orderIndex = 0; orderIndex < nonConstant.size(); orderIndex++) {
|
||||
Order o = nonConstant.get(orderIndex);
|
||||
Expression fieldToOrder = o.child();
|
||||
for (Expression group : a.groupings()) {
|
||||
if (Expressions.equalsAsAttribute(fieldToOrder, group)) {
|
||||
// move grouping in front
|
||||
groupings.remove(group);
|
||||
groupings.add(orderIndex, group);
|
||||
orderChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (orderChanged) {
|
||||
Aggregate newAgg = new Aggregate(a.location(), a.child(), groupings, a.aggregates());
|
||||
return new OrderBy(ob.location(), newAgg, ob.order());
|
||||
}
|
||||
}
|
||||
return ob;
|
||||
}
|
||||
}
|
||||
|
||||
static class CombineLimits extends OptimizerRule<Limit> {
|
||||
|
||||
@Override
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.sql.planner;
|
||||
|
||||
import org.elasticsearch.xpack.sql.expression.Expressions;
|
||||
import org.elasticsearch.xpack.sql.plan.physical.AggregateExec;
|
||||
import org.elasticsearch.xpack.sql.plan.physical.PhysicalPlan;
|
||||
import org.elasticsearch.xpack.sql.plan.physical.Unexecutable;
|
||||
import org.elasticsearch.xpack.sql.plan.physical.UnplannedExec;
|
||||
|
@ -71,23 +69,11 @@ abstract class Verifier {
|
|||
failures.add(fail(e, "Unresolved expression"));
|
||||
}
|
||||
});
|
||||
|
||||
if (p instanceof AggregateExec) {
|
||||
forbidMultiFieldGroupBy((AggregateExec) p, failures);
|
||||
}
|
||||
});
|
||||
|
||||
return failures;
|
||||
}
|
||||
|
||||
private static void forbidMultiFieldGroupBy(AggregateExec a, List<Failure> failures) {
|
||||
if (a.groupings().size() > 1) {
|
||||
failures.add(fail(a.groupings().get(0), "Currently, only a single expression can be used with GROUP BY; please select one of "
|
||||
+ Expressions.names(a.groupings())));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static List<Failure> verifyExecutingPlan(PhysicalPlan plan) {
|
||||
List<Failure> failures = new ArrayList<>();
|
||||
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.sql.planner;
|
||||
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.sql.analysis.analyzer.Analyzer;
|
||||
import org.elasticsearch.xpack.sql.analysis.index.EsIndex;
|
||||
import org.elasticsearch.xpack.sql.analysis.index.IndexResolution;
|
||||
import org.elasticsearch.xpack.sql.expression.function.FunctionRegistry;
|
||||
import org.elasticsearch.xpack.sql.optimizer.Optimizer;
|
||||
import org.elasticsearch.xpack.sql.parser.SqlParser;
|
||||
import org.elasticsearch.xpack.sql.plan.logical.LogicalPlan;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
import org.elasticsearch.xpack.sql.type.EsField;
|
||||
import org.elasticsearch.xpack.sql.type.KeywordEsField;
|
||||
import org.elasticsearch.xpack.sql.type.TextEsField;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public class VerifierErrorMessagesTests extends ESTestCase {
|
||||
|
||||
private SqlParser parser = new SqlParser();
|
||||
private Optimizer optimizer = new Optimizer();
|
||||
private Planner planner = new Planner();
|
||||
|
||||
private String verify(String sql) {
|
||||
Map<String, EsField> mapping = new LinkedHashMap<>();
|
||||
mapping.put("bool", new EsField("bool", DataType.BOOLEAN, Collections.emptyMap(), true));
|
||||
mapping.put("int", new EsField("int", DataType.INTEGER, Collections.emptyMap(), true));
|
||||
mapping.put("text", new TextEsField("text", Collections.emptyMap(), true));
|
||||
mapping.put("keyword", new KeywordEsField("keyword", Collections.emptyMap(), true, DataType.KEYWORD.defaultPrecision, true));
|
||||
EsIndex test = new EsIndex("test", mapping);
|
||||
IndexResolution getIndexResult = IndexResolution.valid(test);
|
||||
Analyzer analyzer = new Analyzer(new FunctionRegistry(), getIndexResult, TimeZone.getTimeZone("UTC"));
|
||||
LogicalPlan plan = optimizer.optimize(analyzer.analyze(parser.createStatement(sql), true));
|
||||
PlanningException e = expectThrows(PlanningException.class, () -> planner.mapPlan(plan, true));
|
||||
assertTrue(e.getMessage().startsWith("Found "));
|
||||
String header = "Found 1 problem(s)\nline ";
|
||||
return e.getMessage().substring(header.length());
|
||||
}
|
||||
|
||||
public void testMultiGroupBy() {
|
||||
assertEquals("1:32: Currently, only a single expression can be used with GROUP BY; please select one of [bool, keyword]",
|
||||
verify("SELECT bool FROM test GROUP BY bool, keyword"));
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ import org.apache.logging.log4j.Logger;
|
|||
import org.elasticsearch.client.RestClient;
|
||||
import org.elasticsearch.xpack.qa.sql.jdbc.CsvTestUtils.CsvTestCase;
|
||||
import org.elasticsearch.xpack.qa.sql.jdbc.DataLoader;
|
||||
import org.elasticsearch.xpack.qa.sql.jdbc.JdbcAssert;
|
||||
import org.elasticsearch.xpack.qa.sql.jdbc.JdbcTestUtils;
|
||||
import org.elasticsearch.xpack.qa.sql.jdbc.SpecBaseIntegrationTestCase;
|
||||
import org.elasticsearch.xpack.qa.sql.jdbc.SqlSpecTestCase;
|
||||
|
||||
|
@ -68,8 +68,8 @@ public class JdbcDocCsvSpectIT extends SpecBaseIntegrationTestCase {
|
|||
//
|
||||
// uncomment this to printout the result set and create new CSV tests
|
||||
//
|
||||
//JdbcTestUtils.logLikeCLI(elastic, log);
|
||||
JdbcAssert.assertResultSets(expected, elastic, log, true);
|
||||
JdbcTestUtils.logLikeCLI(elastic, log);
|
||||
//JdbcAssert.assertResultSets(expected, elastic, log, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -48,6 +48,39 @@ SELECT emp_no * 2 AS e FROM test_emp GROUP BY e ORDER BY e;
|
|||
groupByModScalar
|
||||
SELECT (emp_no % 3) + 1 AS e FROM test_emp GROUP BY e ORDER BY e;
|
||||
|
||||
// multiple group by
|
||||
groupByMultiOnText
|
||||
SELECT gender g, languages l FROM "test_emp" GROUP BY gender, languages ORDER BY gender ASC, languages ASC;
|
||||
groupByMultiOnTextWithWhereClause
|
||||
SELECT gender g, languages l FROM "test_emp" WHERE emp_no < 10020 GROUP BY gender, languages ORDER BY gender ASC, languages ASC;
|
||||
groupByMultiOnTextWithWhereAndLimit
|
||||
SELECT gender g, languages l FROM "test_emp" WHERE emp_no < 10020 GROUP BY gender, languages ORDER BY gender, languages LIMIT 1;
|
||||
groupByMultiOnTextOnAlias
|
||||
SELECT gender g, languages l FROM "test_emp" WHERE emp_no < 10020 GROUP BY g, l ORDER BY gender ASC, languages ASC;
|
||||
groupByMultiOnTextOnAliasOrderDesc
|
||||
SELECT gender g, languages l FROM "test_emp" WHERE emp_no < 10020 GROUP BY g, l ORDER BY g, l ASC;
|
||||
|
||||
groupByMultiOnDate
|
||||
SELECT birth_date b, languages l FROM "test_emp" GROUP BY birth_date, languages ORDER BY birth_date DESC, languages;
|
||||
groupByMultiOnDateWithWhereClause
|
||||
SELECT birth_date b, languages l FROM "test_emp" WHERE emp_no < 10020 GROUP BY birth_date, languages ORDER BY birth_date DESC, languages;
|
||||
groupByMultiOnDateWithWhereAndLimit
|
||||
SELECT birth_date b, languages l FROM "test_emp" WHERE emp_no < 10020 GROUP BY birth_date, languages ORDER BY birth_date DESC, languages LIMIT 1;
|
||||
groupByMultiOnDateOnAlias
|
||||
SELECT birth_date b, languages l FROM "test_emp" WHERE emp_no < 10020 GROUP BY b, l ORDER BY birth_date DESC, languages;
|
||||
|
||||
groupByMultiAddScalar
|
||||
SELECT emp_no + 1 AS e, languages + 5 AS l FROM test_emp GROUP BY e, l ORDER BY e, l;
|
||||
groupByMultiMinScalarDesc
|
||||
SELECT emp_no - 1 AS e, languages - 5 AS l FROM test_emp GROUP BY e, l ORDER BY e DESC, l;
|
||||
groupByMultiAddScalarDesc
|
||||
SELECT emp_no % 2 AS e, languages % 10 AS l FROM test_emp GROUP BY e, l ORDER BY e DESC, l;
|
||||
groupByMultiMulScalar
|
||||
SELECT emp_no * 2 AS e, languages * 2 AS l FROM test_emp GROUP BY e, l ORDER BY e, l;
|
||||
groupByMultiModScalar
|
||||
SELECT (emp_no % 3) + 1 AS e, (languages % 3) + 1 AS l FROM test_emp GROUP BY e, l ORDER BY e, l;
|
||||
|
||||
|
||||
//
|
||||
// Aggregate Functions
|
||||
//
|
||||
|
@ -76,6 +109,18 @@ countDistinct
|
|||
SELECT COUNT(DISTINCT hire_date) AS count FROM test_emp;
|
||||
// end::countDistinct
|
||||
|
||||
aggCountAliasAndWhereClauseMultiGroupBy
|
||||
SELECT gender g, languages l, COUNT(*) c FROM "test_emp" WHERE emp_no < 10020 GROUP BY gender, languages ORDER BY gender, languages;
|
||||
aggCountAliasAndWhereClauseAndLimitMultiGroupBy
|
||||
SELECT gender g, languages l, COUNT(*) c FROM "test_emp" WHERE emp_no < 10020 GROUP BY gender, languages ORDER BY gender, languages LIMIT 1;
|
||||
aggCountAliasWithCastAndFilterMultiGroupBy
|
||||
SELECT gender g, languages l, CAST(COUNT(*) AS INT) c FROM "test_emp" WHERE emp_no < 10020 GROUP BY gender, languages ORDER BY gender, languages;
|
||||
aggCountWithAliasMultiGroupBy
|
||||
SELECT gender g, languages l, COUNT(*) c FROM "test_emp" GROUP BY g, l ORDER BY gender, languages;
|
||||
aggCountWithAliasMultiGroupByDifferentOrder
|
||||
SELECT gender g, languages l, COUNT(*) c FROM "test_emp" GROUP BY g, l ORDER BY languages ASC, gender DESC;
|
||||
|
||||
|
||||
|
||||
// Conditional COUNT
|
||||
aggCountAndHaving
|
||||
|
@ -84,7 +129,6 @@ aggCountAndHavingEquality
|
|||
SELECT gender g, COUNT(*) c FROM "test_emp" GROUP BY g HAVING COUNT(*) = 10 ORDER BY gender;
|
||||
aggCountOnColumnAndHaving
|
||||
SELECT gender g, COUNT(gender) c FROM "test_emp" GROUP BY g HAVING COUNT(gender) > 10 ORDER BY gender;
|
||||
// NOT supported yet since Having introduces a new agg
|
||||
aggCountOnColumnAndWildcardAndHaving
|
||||
SELECT gender g, COUNT(*) c FROM "test_emp" GROUP BY g HAVING COUNT(gender) > 10 ORDER BY gender;
|
||||
aggCountAndHavingOnAlias
|
||||
|
@ -101,15 +145,41 @@ aggCountOnColumnAndHavingBetween
|
|||
SELECT gender g, COUNT(gender) c FROM "test_emp" GROUP BY g HAVING c BETWEEN 10 AND 70 ORDER BY gender;
|
||||
aggCountOnColumnAndHavingBetweenWithLimit
|
||||
SELECT gender g, COUNT(gender) c FROM "test_emp" GROUP BY g HAVING c BETWEEN 10 AND 70 ORDER BY gender LIMIT 1;
|
||||
|
||||
aggCountOnColumnAndHavingOnAliasAndFunction
|
||||
SELECT gender g, COUNT(gender) c FROM "test_emp" GROUP BY g HAVING c > 10 AND COUNT(gender) < 70 ORDER BY gender;
|
||||
// NOT supported yet since Having introduces a new agg
|
||||
aggCountOnColumnAndHavingOnAliasAndFunctionWildcard -> COUNT(*/1) vs COUNT(gender)
|
||||
SELECT gender g, COUNT(gender) c FROM "test_emp" GROUP BY g HAVING c > 10 AND COUNT(*) < 70 ORDER BY gender;
|
||||
aggCountOnColumnAndHavingOnAliasAndFunctionConstant
|
||||
SELECT gender g, COUNT(gender) c FROM "test_emp" GROUP BY g HAVING c > 10 AND COUNT(1) < 70 ORDER BY gender;
|
||||
|
||||
aggCountAndHavingMultiGroupBy
|
||||
SELECT gender g, languages l, COUNT(*) c FROM "test_emp" GROUP BY g, l HAVING COUNT(*) > 10 ORDER BY gender, l;
|
||||
aggCountOnColumnAndHavingMultiGroupBy
|
||||
SELECT gender g, languages l, COUNT(gender) c FROM "test_emp" GROUP BY g, l HAVING COUNT(gender) > 10 ORDER BY gender, languages;
|
||||
aggCountOnSecondColumnAndHavingMultiGroupBy
|
||||
SELECT gender g, languages l, COUNT(languages) c FROM "test_emp" GROUP BY g, l HAVING COUNT(gender) > 10 ORDER BY gender, languages;
|
||||
aggCountOnColumnAndWildcardAndHavingMultiGroupBy
|
||||
SELECT gender g, languages l, COUNT(*) c FROM "test_emp" GROUP BY g, l HAVING COUNT(gender) > 10 ORDER BY gender, languages;
|
||||
aggCountAndHavingOnAliasMultiGroupBy
|
||||
SELECT gender g, languages l, COUNT(*) c FROM "test_emp" GROUP BY g, l HAVING c > 10 ORDER BY gender, languages;
|
||||
aggCountOnColumnAndHavingOnAliasMultiGroupBy
|
||||
SELECT gender g, languages l, COUNT(gender) c FROM "test_emp" GROUP BY g, l HAVING c > 10 ORDER BY gender, languages;
|
||||
aggCountOnColumnAndMultipleHavingMultiGroupBy
|
||||
SELECT gender g, languages l, COUNT(gender) c FROM "test_emp" GROUP BY g, l HAVING c > 10 AND c < 70 ORDER BY gender, languages;
|
||||
aggCountOnColumnAndMultipleHavingWithLimitMultiGroupBy
|
||||
SELECT gender g, languages l, COUNT(gender) c FROM "test_emp" GROUP BY g, l HAVING c > 10 AND c < 70 ORDER BY gender, languages LIMIT 1;
|
||||
aggCountOnColumnAndHavingBetweenMultiGroupBy
|
||||
SELECT gender g, languages l, COUNT(gender) c FROM "test_emp" GROUP BY g, l HAVING c BETWEEN 10 AND 70 ORDER BY gender, languages;
|
||||
aggCountOnColumnAndHavingBetweenWithLimitMultiGroupBy
|
||||
SELECT gender g, languages l, COUNT(gender) c FROM "test_emp" GROUP BY g, l HAVING c BETWEEN 10 AND 70 ORDER BY gender, languages LIMIT 1;
|
||||
|
||||
aggCountOnColumnAndHavingOnAliasAndFunctionMultiGroupBy
|
||||
SELECT gender g, languages l, COUNT(gender) c FROM "test_emp" GROUP BY g, l HAVING c > 10 AND COUNT(gender) < 70 ORDER BY gender, languages;
|
||||
aggCountOnColumnAndHavingOnAliasAndFunctionWildcardMultiGroupBy -> COUNT(*/1) vs COUNT(gender)
|
||||
SELECT gender g, languages l, COUNT(gender) c FROM "test_emp" GROUP BY g, l HAVING c > 10 AND COUNT(*) < 70 ORDER BY gender, languages;
|
||||
aggCountOnColumnAndHavingOnAliasAndFunctionConstantMultiGroupBy
|
||||
SELECT gender g, languages l, COUNT(gender) c FROM "test_emp" GROUP BY g, l HAVING c > 10 AND COUNT(1) < 70 ORDER BY gender, languages;
|
||||
|
||||
|
||||
// MIN
|
||||
aggMinImplicit
|
||||
|
@ -149,6 +219,21 @@ SELECT gender g, MIN(emp_no) m FROM "test_emp" GROUP BY g HAVING m BETWEEN 10 AN
|
|||
aggMinWithMultipleHavingOnAliasAndFunction
|
||||
SELECT gender g, MIN(emp_no) m FROM "test_emp" GROUP BY g HAVING m > 10 AND MIN(emp_no) < 99999 ORDER BY gender;
|
||||
|
||||
aggMinWithHavingGroupMultiGroupBy
|
||||
SELECT gender g, languages l, MIN(emp_no) m FROM "test_emp" GROUP BY g, l HAVING MIN(emp_no) > 10 ORDER BY gender, languages;
|
||||
aggMinWithHavingOnAliasMultiGroupBy
|
||||
SELECT gender g, languages l, MIN(emp_no) m FROM "test_emp" GROUP BY g, l HAVING m > 10 ORDER BY gender, languages;
|
||||
aggMinWithMultipleHavingMultiGroupBy
|
||||
SELECT gender g, languages l, MIN(emp_no) m FROM "test_emp" GROUP BY g, l HAVING m > 10 AND m < 99999 ORDER BY gender, languages;
|
||||
aggMinWithMultipleHavingBetweenMultiGroupBy
|
||||
SELECT gender g, languages l, MIN(emp_no) m FROM "test_emp" GROUP BY g, l HAVING m BETWEEN 10 AND 99999 ORDER BY gender, languages;
|
||||
aggMinWithMultipleHavingWithLimitMultiGroupBy
|
||||
SELECT gender g, languages l, MIN(emp_no) m FROM "test_emp" GROUP BY g, l HAVING m > 10 AND m < 99999 ORDER BY g, l LIMIT 1;
|
||||
aggMinWithMultipleHavingBetweenMultiGroupBy
|
||||
SELECT gender g, languages l, MIN(emp_no) m FROM "test_emp" GROUP BY g, l HAVING m BETWEEN 10 AND 99999 ORDER BY g, l LIMIT 1;
|
||||
aggMinWithMultipleHavingOnAliasAndFunctionMultiGroupBy
|
||||
SELECT gender g, languages l, MIN(emp_no) m FROM "test_emp" GROUP BY g, l HAVING m > 10 AND MIN(emp_no) < 99999 ORDER BY gender, languages;
|
||||
|
||||
|
||||
// MAX
|
||||
aggMaxImplicit
|
||||
|
@ -258,6 +343,8 @@ SELECT gender g, CAST(AVG(emp_no) AS FLOAT) a FROM "test_emp" GROUP BY g HAVING
|
|||
//
|
||||
aggGroupByOnScalarWithHaving
|
||||
SELECT emp_no + 1 AS e FROM test_emp GROUP BY e HAVING AVG(salary) BETWEEN 1 AND 10010 ORDER BY e;
|
||||
aggMultiGroupByOnScalarWithHaving
|
||||
SELECT emp_no + 1 AS e, languages % 10 AS l FROM test_emp GROUP BY e, l HAVING AVG(salary) BETWEEN 1 AND 10010 ORDER BY e, l;
|
||||
|
||||
//
|
||||
// Mixture of Aggs that triggers promotion of aggs to stats
|
||||
|
@ -277,12 +364,34 @@ SELECT MIN(salary) mi, MAX(salary) ma, MAX(salary) - MIN(salary) AS d FROM test_
|
|||
aggHavingScalarOnAggFunctionsWithoutAliasesInAndNotInGroupBy
|
||||
SELECT MIN(salary) mi, MAX(salary) ma, MAX(salary) - MIN(salary) AS d FROM test_emp GROUP BY languages HAVING MAX(salary) % MIN(salary) + AVG(salary) > 3000 ORDER BY languages;
|
||||
|
||||
aggMultiGroupByMultiIncludingScalarFunction
|
||||
SELECT MIN(salary) mi, MAX(salary) ma, MAX(salary) - MIN(salary) AS d FROM test_emp GROUP BY gender, languages ORDER BY gender, languages;
|
||||
aggMultiGroupByHavingWithAggNotInGroupBy
|
||||
SELECT MIN(salary) mi, MAX(salary) ma, MAX(salary) - MIN(salary) AS d FROM test_emp GROUP BY gender, languages HAVING AVG(salary) > 30000 ORDER BY gender, languages;
|
||||
aggMultiGroupByHavingWithAliasOnScalarFromGroupBy
|
||||
SELECT MIN(salary) mi, MAX(salary) ma, MAX(salary) - MIN(salary) AS d FROM test_emp GROUP BY gender, languages HAVING d BETWEEN 50 AND 10000 AND AVG(salary) > 30000 ORDER BY gender, languages;
|
||||
aggMultiGroupByHavingWithScalarFunctionBasedOnAliasFromGroupBy
|
||||
SELECT MIN(salary) mi, MAX(salary) ma, MAX(salary) - MIN(salary) AS d FROM test_emp GROUP BY gender, languages HAVING ma % mi > 1 AND AVG(salary) > 30000 ORDER BY gender, languages;
|
||||
aggMultiGroupByHavingWithMultipleScalarFunctionsBasedOnAliasFromGroupBy
|
||||
SELECT MIN(salary) mi, MAX(salary) ma, MAX(salary) - MIN(salary) AS d FROM test_emp GROUP BY gender, languages HAVING d - ma % mi > 0 AND AVG(salary) > 30000 ORDER BY gender, languages;
|
||||
aggMultiGroupByHavingWithMultipleScalarFunctionsBasedOnAliasFromGroupByAndAggNotInGroupBy
|
||||
SELECT MIN(salary) mi, MAX(salary) ma, MAX(salary) - MIN(salary) AS d FROM test_emp GROUP BY gender, languages HAVING ROUND(d - ABS(ma % mi)) + AVG(salary) > 0 AND AVG(salary) > 30000 ORDER BY gender, languages;
|
||||
aggMultiGroupByHavingScalarOnAggFunctionsWithoutAliasesInAndNotInGroupBy
|
||||
SELECT MIN(salary) mi, MAX(salary) ma, MAX(salary) - MIN(salary) AS d FROM test_emp GROUP BY gender, languages HAVING MAX(salary) % MIN(salary) + AVG(salary) > 3000 ORDER BY gender, languages;
|
||||
|
||||
|
||||
//
|
||||
// Mixture of aggs that get promoted plus filtering on one of them
|
||||
//
|
||||
aggMultiWithHaving
|
||||
SELECT MIN(salary) min, MAX(salary) max, gender g, COUNT(*) c FROM "test_emp" WHERE languages > 0 GROUP BY g HAVING max > 74600 ORDER BY gender;
|
||||
|
||||
aggMultiGroupByMultiWithHaving
|
||||
SELECT MIN(salary) min, MAX(salary) max, gender g, languages l, COUNT(*) c FROM "test_emp" WHERE languages > 0 GROUP BY g, languages HAVING max > 74600 ORDER BY gender, languages;
|
||||
|
||||
|
||||
// filter on count (which is a special agg)
|
||||
aggMultiWithHavingOnCount
|
||||
SELECT MIN(salary) min, MAX(salary) max, gender g, COUNT(*) c FROM "test_emp" WHERE languages > 0 GROUP BY g HAVING c > 40 ORDER BY gender;
|
||||
SELECT MIN(salary) min, MAX(salary) max, gender g, COUNT(*) c FROM "test_emp" WHERE languages > 0 GROUP BY g HAVING c > 40 ORDER BY gender;
|
||||
aggMultiGroupByMultiWithHavingOnCount
|
||||
SELECT MIN(salary) min, MAX(salary) max, gender g, languages l, COUNT(*) c FROM "test_emp" WHERE languages > 0 GROUP BY g, languages HAVING c > 40 ORDER BY gender, languages;
|
|
@ -456,6 +456,27 @@ SELECT languages + 1 AS l FROM emp GROUP BY l;
|
|||
// end::groupByExpression
|
||||
;
|
||||
|
||||
groupByMulti
|
||||
// tag::groupByMulti
|
||||
SELECT gender g, languages l, COUNT(*) c FROM "emp" GROUP BY g, l ORDER BY languages ASC, gender DESC;
|
||||
|
||||
g | l | c
|
||||
---------------+---------------+---------------
|
||||
F |2 |4
|
||||
F |3 |8
|
||||
F |4 |7
|
||||
F |5 |7
|
||||
F |6 |11
|
||||
M |2 |12
|
||||
M |3 |12
|
||||
M |4 |15
|
||||
M |5 |11
|
||||
M |6 |13
|
||||
|
||||
// end::groupByMulti
|
||||
;
|
||||
|
||||
|
||||
groupByAndAgg
|
||||
// tag::groupByAndAgg
|
||||
SELECT gender AS g, COUNT(*) AS c FROM emp GROUP BY gender;
|
||||
|
|
Loading…
Reference in New Issue