#27849 closed New feature (fixed)
Add SQL 2003 FILTER syntax support with Case(When()) fallback to aggregates
Reported by: | Tom Forbes | Owned by: | Tom Forbes |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | dev |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Ready for checkin | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
In some circumstances being able to filter results included in an ArrayAgg is needed. PostgreSQL supports this through the FILTER WHERE clause:
SELECT ARRAY_AGG(id) FILTER (WHERE id < 10) as foo FROM table
Adding support for Q expressions in the ArrayAgg class could provide this functionality, i.e:
SomeModel.objects.annotate(foo=ArrayAgg('some_relation__id', where=Q(some_relation__bar=10)))
Change History (13)
comment:2 by , 8 years ago
For what it's worth, I posted a snippet that solves a more generic version of this at DjangoSnippets a few weeks ago.
https://djangosnippets.org/snippets/10603/ The syntax is not supported on Oracle, MySQL nor SQLite, so I suppose new feature-flags could be introduced etc.
comment:3 by , 8 years ago
Triage Stage: | Unreviewed → Accepted |
---|
You can ask on the DevelopersMailingList to get feedback about the design decisions such as the syntax.
comment:4 by , 8 years ago
I've added a new merge request: https://github.com/django/django/pull/8306. I'm at the Djangocon sprints for the next couple of days if anyone wishes to talk to me in person about this, or has any comments.
comment:5 by , 8 years ago
Component: | contrib.postgres → Database layer (models, ORM) |
---|---|
Has patch: | set |
Owner: | set to |
Patch needs improvement: | set |
Summary: | Support Postgres FILTER WHERE conditions in ArrayAgg → Add SQL 2003 FILTER syntax support with Case(When()) fallback to aggregates |
comment:6 by , 7 years ago
Patch needs improvement: | unset |
---|
comment:7 by , 7 years ago
Patch needs improvement: | set |
---|
comment:8 by , 7 years ago
Owner: | changed from | to
---|---|
Patch needs improvement: | unset |
Status: | new → assigned |
I've made the changes requested in the github ticket, any reviews would be appreciated.
comment:9 by , 7 years ago
Triage Stage: | Accepted → Ready for checkin |
---|
I have added a completely basic, first-attempt at this here: https://github.com/django/django/pull/8073
This currently works as described in the ticket above, but the code is not optimal and is copied from our internal implementation. As this feature is needed for the application I am working on I can continue to develop this, but I have some questions:
Should this be an extension to
ArrayAgg
or a separate aggregate? If it should be an extension, how can I change thetemplate
to add theFILTER (WHERE)
clause if required?There doesn't seem to be an easy way to subclass
ArrayAgg
and add elements todata
orparams
, which is needed in this case. How could this be achieved without duplicating the entireas_sql
code as it is currently? (it seems like theas_sql
method should be broken up a bit, I think?)It would be quite nice to be able to pass a whole, full-fat
QuerySet
into the aggregate, with the predicate that it is has beenvalues_list
'ed and is a relation of the model being queried (i.eSomeModel.objects.annotate(foo=ArrayAgg(SomeRelation.objects.filter(parent=F('id')).filter(something=something_else).values_list('xyz'))
or somesuch. Is this even possible, or would it be chewing off too much?Oh, and is this a feature that Django even wants?