Is there a way to make SQLAlchemy generate a query with a custom column that is a subquery that correlates with current row:
SELECT
tab1.id,
tab1.col1,
...,
(
SELECT count(1) FROM tab2
WHERE tab2.tab1_id = tab1.id
GROUP BY tab2.col1
) as cnt
FROM tab1
WHERE ...
LIMIT 100
using the ORM API?
session.query(Tab1, ?(subquery for additional column)?).filter(...).limit(100)
I'm using PostgreSQL 9.3 and old version of SQLAlchemy 0.9.8
The select list of a subquery introduced with a comparison operator can include only one expression or column name (except that EXISTS and IN operate on SELECT * or a list, respectively). If the WHERE clause of an outer query includes a column name, it must be join-compatible with the column in the subquery select list.
You can use a subquery in the FROM clause of the SELECT statement as follows: SELECT * FROM (subquery) AS table_name Code language: SQL (Structured Query Language) (sql) In this syntax, the table alias is mandatory because all tables in the FROM clause must have a name.
The SQL EXISTS keyword is an operator that is used with scalar subqueries to return a boolean true or false depending on if the SELECT statement would return a row. SQLAlchemy includes a variant of the ScalarSelect object called Exists, which will generate an EXISTS subquery and is most conveniently generated using the SelectBase.exists () method.
A subquery nested in the outer SELECT statement has the following components: A regular SELECT query including the regular select list components. A regular FROM clause including one or more table or view names. An optional WHERE clause. An optional GROUP BY clause.
If you need this often, and/or the count is an integral part of your Tab1
model, you should use a hybrid property such as described in the other answer. If on the other hand you need this just for a single query, then you could just create the scalar subquery using Query.label()
, or Query.as_scalar()
:
count_stmt = session.query(func.count(1)).\
filter(Tab2.tab1_id == Tab1.id).\
group_by(Tab2.col1).\
label('cnt')
session.query(Tab1, count_stmt).filter(...).limit(100)
The subquery will automatically correlate what it can from the enclosing query.
You can do this, but it works in a quite different way to how you have written it. You can create a property of Tab1 which depends on the relationship to tab2 (assuming that tab2.tab1_id
is a foreign key, which it should be.
Your models look like this:
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
children = relationship("Child")
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('parent.id'))
as per the docs on relationships
Then you can add something like
@hybrid_property
def number_of_children(self):
if self.children:
return len(self.children)
return 0
@number_of_children.expression
def number_of_children(cls):
return (select([func.count(Child.id)])
.where(Child.cover_id == cls.id))
to the Parent model, as per this answer and more docs.
Once you've done this, you can filter on this property the same as any other column-based one.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With