Hi,
I have this function which returns a list of product variants and the first
"seasons" they were introduced in (might be multiple on the same date, so
I'm ranking by from_date in a CTE):
*In [190]: def variants_first_seasons_query():*
* ...: ranking_query = (*
* ...: db.session.query(*
* ...: db.ProductVariant.id.label('productvariant_id'),*
* ...: db.ProductSeason.id.label('productseason_id'),*
* ...: db.sqla.func.rank()*
* ...: .over(*
* ...: partition_by=db.ProductVariant.id,*
* ...: order_by=db.ProductSeason.from_date*
* ...: )*
* ...: .label('ranking')*
* ...: )*
* ...: .select_from(db.ProductSeason)*
* ...: .join(db.ProductSeason.skus)*
* ...: .join(db.ProductSKU.variant)*
* ...: .order_by(db.ProductVariant.id)*
* ...: .distinct()*
* ...: )*
* ...: ranking_query_cte = db.sqla.aliased(ranking_query.cte(),
name='ranking_query')*
* ...: return (*
* ...: db.session.query(*
* ...: ranking_query_cte.c.productvariant_id,*
* ...: ranking_query_cte.c.productseason_id*
* ...: )*
* ...: .select_from(ranking_query_cte)*
* ...: .filter(ranking_query_cte.c.ranking == 1)*
* ...: )*
* ...:*
*In [191]: q = variants_first_seasons_query()*
*In [192]: print(q)*
*WITH anon_1 AS*
*(SELECT DISTINCT productvariant.id AS productvariant_id, productseason.id
AS productseason_id, rank() OVER (PARTITION BY productvariant.id ORDER BY
productseason.from_date) AS ranking*
*FROM productseason JOIN productseason_productsku AS
productseason_productsku_1 ON productseason.id =
productseason_productsku_1.productseason_id JOIN productsku ON
productsku.id = productseason_productsku_1.productsku_id JOIN
productvariant ON productvariant.id = productsku.variant_id ORDER BY
productvariant.id)*
* SELECT ranking_query.productvariant_id AS
ranking_query_productvariant_id, ranking_query.productseason_id AS
ranking_query_productseason_id*
*FROM anon_1 AS ranking_query*
*WHERE ranking_query.ranking = %(ranking_1)s*
Later in my code I want to further filter on the seasons that I care about
in the outer query, but as there's no standard declarative model in the
selectable I don't think I can pass the model's attribute in the filter,
but instead I figure I should go through *.statement.c* of the query:
*In [193]: SEASON_IDS = [45]*
*In [194]: q = q.filter(q.statement.c.productseason_id.in_(SEASON_IDS))*
*In [195]: print(q)*
*WITH anon_1 AS*
*(SELECT DISTINCT productvariant.id AS productvariant_id, productseason.id
AS productseason_id, rank() OVER (PARTITION BY productvariant.id ORDER BY
productseason.from_date) AS ranking*
*FROM productseason JOIN productseason_productsku AS
productseason_productsku_1 ON productseason.id =
productseason_productsku_1.productseason_id JOIN productsku ON
productsku.id = productseason_productsku_1.productsku_id JOIN
productvariant ON productvariant.id = productsku.variant_id ORDER BY
productvariant.id)*
* SELECT ranking_query.productvariant_id AS
ranking_query_productvariant_id, ranking_query.productseason_id AS
ranking_query_productseason_id*
*FROM anon_1 AS ranking_query, (SELECT ranking_query.productvariant_id AS
productvariant_id, ranking_query.productseason_id AS productseason_id*
*FROM ranking_query*
*WHERE ranking_query.ranking = %(ranking_1)s)*
*WHERE ranking_query.ranking = %(ranking_1)s AND productseason_id IN
(%(productseason_id_1)s)*
*In [196]: q.count()*
*...*
*ProgrammingError: (psycopg2.ProgrammingError) subquery in FROM must have
an alias*
*LINE 5: FROM anon_1 AS ranking_query, (SELECT ranking_query.productv...*
*...*
No success (as you can see the red part above is the reason).
However I have found a workaround which produces exactly the query I'm
looking for:
*In [197]: db.session.rollback()*
*In [198]: q = variants_first_seasons_query()*
*In [199]: col = [c['expr'] for c in q.column_descriptions if
c['expr'].name == 'productseason_id'][0*
* ...: ]*
*In [200]: q = q.filter(col.in_(SEASON_IDS))*
*In [201]: print(q)*
*WITH anon_1 AS*
*(SELECT DISTINCT productvariant.id AS productvariant_id, productseason.id
AS productseason_id, rank() OVER (PARTITION BY productvariant.id ORDER BY
productseason.from_date) AS ranking*
*FROM productseason JOIN productseason_productsku AS
productseason_productsku_1 ON productseason.id =
productseason_productsku_1.productseason_id JOIN productsku ON
productsku.id = productseason_productsku_1.productsku_id JOIN
productvariant ON productvariant.id = productsku.variant_id ORDER BY
productvariant.id)*
* SELECT ranking_query.productvariant_id AS
ranking_query_productvariant_id, ranking_query.productseason_id AS
ranking_query_productseason_id*
*FROM anon_1 AS ranking_query*
*WHERE ranking_query.ranking = %(ranking_1)s AND
ranking_query.productseason_id IN (%(productseason_id_1)s)*
*In [202]: q.count()*
*Out[202]: 165*
Now my question is, how can accomplish this cleanly, without going through
*.column_descriptions*?
Any suggestions would be greatly appreciated ❤
--
SQLAlchemy -
The Python SQL Toolkit and Object Relational Mapper
http://www.sqlalchemy.org/
To post example code, please provide an MCVE: Minimal, Complete, and Verifiable
Example. See http://stackoverflow.com/help/mcve for a full description.
---
You received this message because you are subscribed to the Google Groups
"sqlalchemy" 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].
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.