mirror of https://github.com/django/django.git
Refs #31150 -- Enabled implicit GROUP BY aliases.
This ensures implicit grouping from aggregate function annotations groups by uncollapsed selected aliases if supported. The feature is disabled on Oracle because it doesn't support it.
This commit is contained in:
parent
3d734c09ff
commit
b7b28c7c18
|
@ -123,6 +123,7 @@ class SQLCompiler:
|
||||||
if self.query.group_by is None:
|
if self.query.group_by is None:
|
||||||
return []
|
return []
|
||||||
expressions = []
|
expressions = []
|
||||||
|
allows_group_by_refs = self.connection.features.allows_group_by_refs
|
||||||
if self.query.group_by is not True:
|
if self.query.group_by is not True:
|
||||||
# If the group by is set to a list (by .values() call most likely),
|
# If the group by is set to a list (by .values() call most likely),
|
||||||
# then we need to add everything in it to the GROUP BY clause.
|
# then we need to add everything in it to the GROUP BY clause.
|
||||||
|
@ -132,20 +133,21 @@ class SQLCompiler:
|
||||||
for expr in self.query.group_by:
|
for expr in self.query.group_by:
|
||||||
if not hasattr(expr, "as_sql"):
|
if not hasattr(expr, "as_sql"):
|
||||||
expr = self.query.resolve_ref(expr)
|
expr = self.query.resolve_ref(expr)
|
||||||
if not self.connection.features.allows_group_by_refs and isinstance(
|
if not allows_group_by_refs and isinstance(expr, Ref):
|
||||||
expr, Ref
|
|
||||||
):
|
|
||||||
expr = expr.source
|
expr = expr.source
|
||||||
expressions.append(expr)
|
expressions.append(expr)
|
||||||
# Note that even if the group_by is set, it is only the minimal
|
# Note that even if the group_by is set, it is only the minimal
|
||||||
# set to group by. So, we need to add cols in select, order_by, and
|
# set to group by. So, we need to add cols in select, order_by, and
|
||||||
# having into the select in any case.
|
# having into the select in any case.
|
||||||
ref_sources = {expr.source for expr in expressions if isinstance(expr, Ref)}
|
ref_sources = {expr.source for expr in expressions if isinstance(expr, Ref)}
|
||||||
for expr, _, _ in select:
|
aliased_exprs = {}
|
||||||
|
for expr, _, alias in select:
|
||||||
# Skip members of the select clause that are already included
|
# Skip members of the select clause that are already included
|
||||||
# by reference.
|
# by reference.
|
||||||
if expr in ref_sources:
|
if expr in ref_sources:
|
||||||
continue
|
continue
|
||||||
|
if alias:
|
||||||
|
aliased_exprs[expr] = alias
|
||||||
cols = expr.get_group_by_cols()
|
cols = expr.get_group_by_cols()
|
||||||
for col in cols:
|
for col in cols:
|
||||||
expressions.append(col)
|
expressions.append(col)
|
||||||
|
@ -163,6 +165,8 @@ class SQLCompiler:
|
||||||
expressions = self.collapse_group_by(expressions, having_group_by)
|
expressions = self.collapse_group_by(expressions, having_group_by)
|
||||||
|
|
||||||
for expr in expressions:
|
for expr in expressions:
|
||||||
|
if allows_group_by_refs and (alias := aliased_exprs.get(expr)):
|
||||||
|
expr = Ref(alias, expr)
|
||||||
try:
|
try:
|
||||||
sql, params = self.compile(expr)
|
sql, params = self.compile(expr)
|
||||||
except EmptyResultSet:
|
except EmptyResultSet:
|
||||||
|
|
|
@ -1639,12 +1639,12 @@ class AggregateTestCase(TestCase):
|
||||||
)
|
)
|
||||||
.annotate(count=Count("authors"))
|
.annotate(count=Count("authors"))
|
||||||
)
|
)
|
||||||
self.assertSequenceEqual(books_qs, [book])
|
with self.assertNumQueries(1) as ctx:
|
||||||
# FIXME: GROUP BY doesn't need to include a subquery with
|
self.assertSequenceEqual(books_qs, [book])
|
||||||
# non-multivalued JOINs, see Col.possibly_multivalued (refs #31150):
|
# Outerquery SELECT, annotation SELECT, and WHERE SELECT but GROUP BY
|
||||||
# with self.assertNumQueries(1) as ctx:
|
# selected alias, if allowed.
|
||||||
# self.assertSequenceEqual(books_qs, [book])
|
if connection.features.allows_group_by_refs:
|
||||||
# self.assertEqual(ctx[0]['sql'].count('SELECT'), 2)
|
self.assertEqual(ctx[0]["sql"].count("SELECT"), 3)
|
||||||
|
|
||||||
@skipUnlessDBFeature("supports_subqueries_in_group_by")
|
@skipUnlessDBFeature("supports_subqueries_in_group_by")
|
||||||
def test_aggregation_nested_subquery_outerref(self):
|
def test_aggregation_nested_subquery_outerref(self):
|
||||||
|
|
Loading…
Reference in New Issue