#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 , 9 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 , 9 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 , 9 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 , 9 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 , 8 years ago
| Patch needs improvement: | unset |
|---|
comment:7 by , 8 years ago
| Patch needs improvement: | set |
|---|
comment:8 by , 8 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 , 8 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
ArrayAggor a separate aggregate? If it should be an extension, how can I change thetemplateto add theFILTER (WHERE)clause if required?There doesn't seem to be an easy way to subclass
ArrayAggand add elements todataorparams, which is needed in this case. How could this be achieved without duplicating the entireas_sqlcode as it is currently? (it seems like theas_sqlmethod should be broken up a bit, I think?)It would be quite nice to be able to pass a whole, full-fat
QuerySetinto 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('some_relation__id', where=SomeRelation.objects.filter(parent=F('id')).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?