Sqlalchemy: subquery in FROM must have an alias
You are almost there. Make a "selectable" subquery and join it with the main query via join()
:
foo_max_time_q = select([func.max(Foo.time).label('foo_max_time'), Foo.id.label('foo_id') ]).group_by(Foo.id ).alias("foo_max_time_q")foo_q = session.query( Foo.id.label('foo_id'), Foo.version.label('foo_version'), Foo.revision.label('foo_revision'), foo_max_time_q.c.foo_max_time.label('foo_max_time') ).join(foo_max_time_q, foo_max_time_q.c.foo_id == Foo.id)print(foo_q.__str__())
Prints (prettified manually):
SELECT foo.id AS foo_id, foo.version AS foo_version, foo.revision AS foo_revision, foo_max_time_q.foo_max_time AS foo_max_time FROM foo JOIN (SELECT max(foo.time) AS foo_max_time, foo.id AS foo_id FROM foo GROUP BY foo.id) AS foo_max_time_q ON foo_max_time_q.foo_id = foo.id
The complete working code is available in this gist.
Cause
subquery in FROM must have an alias
This error means the subquery (on which we're trying to perform a join
) has no alias.
Even if we .alias('t')
it just to satisfy this requirement, we will then get the next error:
missing FROM-clause entry for table "foo"
That's because the join on
clause (... == Foo.id
) is not familiar with Foo
.
It only knows the "left" and "right" tables: t
(the subquery) and foo_max_time_q
.
Solution
Instead, select_from
a join of Foo
and foo_max_time_q
.
Method 1
Replace .join(B, on_clause)
with .select_from(B.join(A, on_clause)
:
]).join(foo_max_time_q, foo_max_time_q.c.foo_id == Foo.id
]).select_from(foo_max_time_q.join(Foo, foo_max_time_q.c.foo_id == Foo.id)
This works here because A INNER JOIN B
is equivalent to B INNER JOIN A
.
Method 2
To preserve the order of joined tables:
from sqlalchemy import join
and replace .join(B, on_clause)
with .select_from(join(A, B, on_clause))
:
]).join(foo_max_time_q, foo_max_time_q.c.foo_id == Foo.id
]).select_from(join(Foo, foo_max_time_q, foo_max_time_q.c.foo_id == Foo.id)
Alternatives to session.query() can be found here.