16

i need a little help. I have following query and i'm, curious about how to represent it in terms of sqlalchemy.orm. Currently i'm executing it by session.execute. Its not critical for me, but i'm just curious. The thing that i'm actually don't know is how to put subquery in FROM clause (nested view) without doing any join.

select g_o.group_ from (
    select  distinct regexp_split_to_table(g.group_name, E',') group_
        from (
            select array_to_string(groups, ',') group_name
            from company
            where status='active'
            and   array_to_string(groups, ',') like :term
            limit :limit
        ) g
    ) g_o
where g_o.group_ like :term
order by 1
limit :limit

I need this subquery thing because of speed issue - without limit in the most inner query function regexp_split_to_table starts to parse all data and does limit only after that. But my table is huge and i cannot afford that.

If something is not very clear, please, ask, i'll do my best)

1 Answer 1

23

I presume this is PostgreSQL.

To create a subquery, use subquery() method. The resulting object can be used as if it were Table object. Here's how your query would look like in SQLAlchemy:

subq1 = session.query(
    func.array_to_string(Company.groups, ',').label('group_name')
).filter(
    (Company.status == 'active') &
    (func.array_to_string(Company.groups, ',').like(term))
).limit(limit).subquery()

subq2 = session.query(
    func.regexp_split_to_table(subq1.c.group_name, ',')
        .distinct()
        .label('group')
).subquery()

q = session.query(subq2.c.group).\
    filter(subq2.c.group.like(term)).\
    order_by(subq2.c.group).\
    limit(limit)

However, you could avoid one subquery by using unnest function instead of converting array to string with arrayt_to_string and then splitting it with regexp_split_to_table:

subq = session.query(
    func.unnest(Company.groups).label('group')
).filter(
    (Company.status == 'active') &
    (func.array_to_string(Company.groups, ',').like(term))
).limit(limit).subquery()

q = session.query(subq.c.group.distinct()).\
    filter(subq.c.group.like(term)).\
    order_by(subq.c.group).\
    limit(limit)
Sign up to request clarification or add additional context in comments.

2 Comments

One important piece that wasn't explicitly mentioned (but could be inferred from the samples): you need to explicitly use subq1.c instead of subq1 to use the query as a subquery table, else the query won't compile due to missing attributes. See this doc for details.
Notice that Session.query is legacy in SQLAlchemy 2.0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.