#29262: Custom Left Outer Join in Queries
-------------------------------------+-------------------------------------
Reporter: Sassan Haradji | Owner: nobody
Type: New feature | Status: new
Component: Database layer | Version:
(models, ORM) |
Severity: Normal | Resolution:
Keywords: ORM Join | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Sassan Haradji):
Unfortunately I don't think so. What I needed was exactly left join.
The query I needed was a rather complicated query, I try to abstract it
here so that we can investigate it and find out what's needed in Django
ORM to achieve it.
Suppose that I have this table:
{{{
CREATE TABLE foo(id,related_id,value,type)
AS VALUES
( 1 , 1, 'A1' , 1 ),
( 2 , 1, 'A2' , 2 ),
( 3 , 1, 'A3' , 3 ),
( 4 , 1, 'A4' , 4 ),
( 5 , 1, 'A5' , 5 ),
( 6 , 2, 'B1' , 1 ),
( 7 , 2, 'B2' , 2 ),
( 8 , 2, 'B3' , 3 ),
( 9 , 2, 'B4' , 4 ),
( 10, 2, 'B5' , 5 )
;
}}}
I want to aggregate these values and make this intermediate table:
{{{
-----------------------------------------------------------------------------
| id | related_id | values
|
-----------------------------------------------------------------------------
| 1 | 1 | (('A1',1),('A2',2),('A3',3),('A4',4),('A5',5))
|
-----------------------------------------------------------------------------
| 6 | 2 | (('B1',1),('B2',2),('B3',3),('B4',4),('B5',5))
|
-----------------------------------------------------------------------------
}}}
To do so I need to do a simple aggregation:
{{{
foo.objects.values('related_id').annotate(
id=Min('id'),
values=ArrayAgg(
Func(
'value',
'type',
function='ARRAY',
template='%(function)s[%(expressions)s]',
arg_joiner=',',
), output_field=ArrayField(ArrayField(models.FloatField())),
),
)
}}}
This will generate this sql query (or something equivalent):
{{{
SELECT t.*
FROM (
SELECT
min(id),
related_id,
array_agg(ARRAY(value, type)) AS values,
FROM foo
GROUP BY id
) AS t
}}}
So far so good. Then I want to order this query based on value column but
this order should order values of this column that are in a row that has
type=X. I can do so by this sql:
{{{
SELECT t1.*
FROM (
SELECT
min(id),
related_id,
array_agg(ARRAY(value, type)) AS values,
FROM foo
GROUP BY id
) AS t1
LEFT OUTER JOIN (SELECT value FROM foo WHERE type=X) AS t2 USING (id)
ORDER BY t2.value
}}}
This is where I need this left join. It should be left join cause I don't
wanna miss rows that don't have X type value.
Now do you think it's possible to do the above with current Django ORM
API?
Consider that this table is really big, and the above sql query is the
only one I found that executes in rational time and doesn't miss anything.
Also the real problem is much more complected, the number of columns that
are involved are much more so if you think there's room for simplifying
the above sql solution consider that in my real usecase it may not be
applicable so I please lets concentrate on interpreting the exact above
query into Django ORM API and not change the sql query so that it fits the
API.
--
Ticket URL: <https://code.djangoproject.com/ticket/29262#comment:11>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/065.e88defa24661d0066f9179754a6e7aea%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.