Join on a CTE in SQLAlchemy

懵懂的女人 提交于 2020-12-15 06:41:46

问题


I'm trying to formulate a SQLAlchemy query that uses a CTE to build a table-like structure of an input list of tuples, and JOIN it with one of my tables (backend DB is Postgres). Conceptually, it would look like:

WITH to_compare AS (
  SELECT * FROM (
    VALUES 
     (1, 'flimflam'),
     (2, 'fimblefamble'),
     (3, 'pigglywiggly'),
     (4, 'beepboop')
     -- repeat for a couple dozen or hundred rows
  ) AS t (field1, field2)
)
SELECT b.field1, b.field2, b.field3
FROM my_model b
JOIN to_compare c ON (c.field1 = b.field1) AND (c.field2 = b.field2)

The goal is to see what field3 for the pair (field1, field2) in the table if it is, for a medium-sized list of (field1, field2) pairs.

In SQLAlchemy I'm trying to do it like this:

stmts = [
    sa.select(
        [
            sa.cast(sa.literal(field1), sa.Integer).label("field1"),
            sa.cast(sa.literal(field2), sa.Text).label("field2"),
        ]
    )
    if idx == 0
    else sa.select([sa.literal(field1), sa.literal(field2)])
    for idx, (field1, field2) in enumerate(list_of_tuples)
]
cte = sa.union_all(*stmts).cte(name="temporary_table")

already_in_db_query = db.session.query(MyModel)\
    .join(cte,
          cte.c.field1 == MyModel.field1,
          cte.c.field2 == MyModel.field2,
    ).all()

But it seems like CTEs and JOINs don't play well together: the error is on the join, saying:

sqlalchemy.exc.InvalidRequestError: Don't know how to join to ; please use an ON clause to more clearly establish the left side of this join

And if I try to print the cte, it does look like a non-SQL entity:

$ from pprint import pformat
$ print(pformat(str(cte)), flush=True)
> ''

Is there a way to do this? Or a better way to achieve my goal?


回答1:


The second argument to Query.join() should in this case be the full ON clause, but instead you pass 3 arguments to join(). Use and_() to combine the predicates, as is done in the raw SQL:

already_in_db_query = db.session.query(MyModel)\
    .join(cte,
          and_(cte.c.field1 == MyModel.field1,
               cte.c.field2 == MyModel.field2),
    ).all()


来源:https://stackoverflow.com/questions/60387765/join-on-a-cte-in-sqlalchemy

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!