Using Django 4.2 with MSSQL 2019 Aggregation Containing Subquery Fails
haldunk opened this issue · 1 comments
There are some features which are not supported yet. Please check the Limitations first to see if your bug is listed.
Software versions
- Django: 4.2
- mssql-django: 1.3
- python: 3.8
- SQL Server: 2019
- OS: Linux amd64
Table schema and Model
class Exchange(models.Model):
date = models.DateField()
value = models.FloatField()
class Invoice(models.Model):
date = models.DateField()
gross = models.FloatField()
Database Connection Settings
'default': {
'ENGINE': 'mssql',
'NAME': 'db',
'USER': 'SA',
'PASSWORD': '555',
'HOST': 'mssql\MSSQLSERVER',
'PORT': '1433',
'AUTOCOMMIT': True,
'OPTIONS': {
'driver': 'ODBC Driver 17 for SQL Server',
'unicode_results': True,
'host_is_server': True,
'extra_params': 'tds_version=7.4;',
'use_legacy_datetime': False,
'connection_timeout': 300,
'connection_retries': 10,
'connection_retry_backoff_time': 5,
'query_timeout': 300,
},
Problem description and steps to reproduce
Aggregation in a query employing a subquery expression fails with the following error:
ProgrammingError: ('42000', '[42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Cannot perform an aggregate function on an expression containing an aggregate or a subquery. (130) (SQLExecDirectW)')
However, the same query works in Django 4.1.10.
exchange = Subquery(Exchange.objects.filter(date__lte=OuterRef('date')).order_by('-date').values('value')[:1])
Invoice.objects.annotate(
exchange=exchange,
gross_currency=F('gross') / F('exchange')
).aggregate(
avg_gross_currency=Avg('gross_currency')
)
Expected behavior and actual behavior
Error message/stack trace
ProgrammingError Traceback (most recent call last)
File /usr/local/lib/python3.8/dist-packages/django/db/backends/utils.py:89, in CursorWrapper._execute(self, sql, params, *ignored_wrapper_args)
88 else:
---> 89 return self.cursor.execute(sql, params)
File /usr/local/lib/python3.8/dist-packages/mssql/base.py:619, in CursorWrapper.execute(self, sql, params)
618 try:
--> 619 return self.cursor.execute(sql, params)
620 except Database.Error as e:
ProgrammingError: ('42000', '[42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Cannot perform an aggregate function on an expression containing an aggregate or a subquery. (130) (SQLExecDirectW)')
The above exception was the direct cause of the following exception:
ProgrammingError Traceback (most recent call last)
Cell In[10], line 1
----> 1 july_invoices.annotate(net_eur=F('net_lira')/eurtry).aggregate(a_net_eur=Avg('net_eur'))
File /usr/local/lib/python3.8/dist-packages/django/db/models/query.py:592, in QuerySet.aggregate(self, *args, **kwargs)
589 raise TypeError("Complex aggregates require an alias")
590 kwargs[arg.default_alias] = arg
--> 592 return self.query.chain().get_aggregation(self.db, kwargs)
File /usr/local/lib/python3.8/dist-packages/django/db/models/sql/query.py:554, in Query.get_aggregation(self, using, aggregate_exprs)
552 outer_query.select_related = False
553 compiler = outer_query.get_compiler(using, elide_empty=elide_empty)
--> 554 result = compiler.execute_sql(SINGLE)
555 if result is None:
556 result = empty_set_result
File /usr/local/lib/python3.8/dist-packages/django/db/models/sql/compiler.py:1562, in SQLCompiler.execute_sql(self, result_type, chunked_fetch, chunk_size)
1560 cursor = self.connection.cursor()
1561 try:
-> 1562 cursor.execute(sql, params)
1563 except Exception:
1564 # Might fail for server-side cursors (e.g. connection closed)
1565 cursor.close()
File /usr/local/lib/python3.8/dist-packages/django/db/backends/utils.py:67, in CursorWrapper.execute(self, sql, params)
66 def execute(self, sql, params=None):
---> 67 return self._execute_with_wrappers(
68 sql, params, many=False, executor=self._execute
69 )
File /usr/local/lib/python3.8/dist-packages/django/db/backends/utils.py:80, in CursorWrapper._execute_with_wrappers(self, sql, params, many, executor)
78 for wrapper in reversed(self.db.execute_wrappers):
79 executor = functools.partial(wrapper, executor)
---> 80 return executor(sql, params, many, context)
File /usr/local/lib/python3.8/dist-packages/django/db/backends/utils.py:89, in CursorWrapper._execute(self, sql, params, *ignored_wrapper_args)
87 return self.cursor.execute(sql)
88 else:
---> 89 return self.cursor.execute(sql, params)
File /usr/local/lib/python3.8/dist-packages/django/db/utils.py:91, in DatabaseErrorWrapper.exit(self, exc_type, exc_value, traceback)
89 if dj_exc_type not in (DataError, IntegrityError):
90 self.wrapper.errors_occurred = True
---> 91 raise dj_exc_value.with_traceback(traceback) from exc_value
File /usr/local/lib/python3.8/dist-packages/django/db/backends/utils.py:89, in CursorWrapper._execute(self, sql, params, *ignored_wrapper_args)
87 return self.cursor.execute(sql)
88 else:
---> 89 return self.cursor.execute(sql, params)
File /usr/local/lib/python3.8/dist-packages/mssql/base.py:619, in CursorWrapper.execute(self, sql, params)
617 self.last_params = params
618 try:
--> 619 return self.cursor.execute(sql, params)
620 except Database.Error as e:
621 self.connection._on_error(e)
ProgrammingError: ('42000', '[42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Cannot perform an aggregate function on an expression containing an aggregate or a subquery. (130) (SQLExecDirectW)')
Any other details that can be helpful
Thanks for the report. Will look into this