Advanced Queries in SQLAlchemy (Filters, Joins, Aggregations, Subqueries)

 

Advanced Queries in SQLAlchemy (Filters, Joins, Aggregations, Subqueries)

Introduction

Once you know basic CRUD, the next step is writing powerful, real-world database queries.

In this blog, you’ll learn:

  • Advanced filtering
  • Joins (INNER, LEFT)
  • Aggregations (COUNT, SUM, AVG)
  • Subqueries & nested queries
  • Performance tips

Sample Models (Setup)

We’ll use two tables:

from sqlalchemy import Column, Integer, String, ForeignKey

from sqlalchemy.orm import declarative_base, relationship

Base = declarative_base()

class User(Base):

    __tablename__ = "users"

    id = Column(Integer, primary_key=True)

    name = Column(String)

    orders = relationship("Order", back_populates="user")


class Order(Base):

    __tablename__ = "orders"

    id = Column(Integer, primary_key=True)

    amount = Column(Integer)

    user_id = Column(Integer, ForeignKey("users.id"))

    user = relationship("User

1. Advanced Filtering

Basic Filter

session.query(User).filter(User.name == "John").all()

Multiple Conditions

from sqlalchemy import and_, or_

# AND condition
session.query(User).filter(
and_(User.name == "John", User.id > 1)
).all()

# OR condition
session.query(User).filter(
or_(User.name == "John", User.name == "Alice")
).all()

LIKE (Search)

session.query(User).filter(User.name.like("%Jo%")).all()

IN Operator

session.query(User).filter(User.id.in_([1, 2, 3])).all()

NOT / !=

session.query(User).filter(User.name != "John").all()

", back_populates="orders")


2. Joins

What is a Join?

A join combines data from multiple tables.

INNER JOIN

session.query(User).join(Order).all()

Returns users who have orders

Fetch User + Order Data

results = session.query(User, Order).join(Order).all()

for user, order in results:
print(user.name, order.amount)

LEFT JOIN

session.query(User).outerjoin(Order).all()

Returns all users (even those without orders)

Real-World Example

Get users who placed orders above ₹500:

session.query(User).join(Order).filter(Order.amount > 500).all()


3. Aggregations (COUNT, SUM, AVG)

from sqlalchemy import func

COUNT

session.query(func.count(User.id)).scalar()

SUM

session.query(func.sum(Order.amount)).scalar()

AVG

session.query(func.avg(Order.amount)).scalar()

GROUP BY

session.query(
Order.user_id,
func.sum(Order.amount)
).group_by(Order.user_id).all()

Total order amount per user

HAVING

session.query(
Order.user_id,
func.sum(Order.amount).label("total")
).group_by(Order.user_id).having(func.sum(Order.amount) > 1000).all()

Users with total orders > ₹1000

4. Subqueries

What is a Subquery?

A query inside another query.

Example: Users with High Orders

subquery = session.query(Order.user_id).filter(Order.amount > 500).subquery()

session.query(User).filter(User.id.in_(subquery)).all()

Using Alias

from sqlalchemy.orm import aliased

OrderAlias = aliased(Order)

session.query(User).join(OrderAlias).all()

5. Lazy vs Eager Loading

Problem (N+1 Query Issue)

users = session.query(User).all()

for user in users:
print(user.orders) # multiple queries!

Solution: Eager Loading

from sqlalchemy.orm import joinedload

users = session.query(User).options(joinedload(User.orders)).all()

Loads everything in one query

6. Ordering & Limiting Results

ORDER BY

session.query(User).order_by(User.name).all()

DESC Order

from sqlalchemy import desc

session.query(User).order_by(desc(User.id)).all()

LIMIT

session.query(User).limit(5).all()

OFFSET (Pagination)

session.query(User).offset(5).limit(5).all()

Real-World Use Case

E-commerce Example :Top 5 users who spent the most:

session.query(
User.name,
func.sum(Order.amount).label("total")
).join(Order).group_by(User.id)\
.order_by(desc("total"))\
.limit(5).all()

Common Mistakes

  • Using .all() when .first() is enough
  • Not using indexes in DB
  • Ignoring N+1 query problem
  • Writing inefficient joins

Comments

Popular posts from this blog

Database Integration in FastAPI (SQLAlchemy CRUD)

Middleware & CORS in FastAPI

Python Data Handling