SQLAlchemy: How to Sort Results by Multiple Columns

Updated: January 3, 2024 By: Guest Contributor Post a comment

Introduction

SQLAlchemy is a powerful ORM used for database operations in Python. This tutorial will guide you through sorting query results by multiple columns, applying principles that cater to basic and advanced use cases alike.

Basic Sorting: Single Column

Before diving into sorting by multiple columns, let’s start with the basics of sorting by a single column. Sorting in SQLAlchemy can be done using the order_by() method. Here is a simple example using User model to sort by the username column:

from sqlalchemy import create_engine, asc
from sqlalchemy.orm import sessionmaker
from yourapp.models import User

engine = create_engine('sqlite:///yourdatabase.db')
Session = sessionmaker(bind=engine)
session = Session()

query = session.query(User).order_by(User.username)

In the code above, asc() is used to denote an ascending sort, which is actually the default if omitted. Replace asc() with desc() to sort in descending order.

Sorting by Multiple Columns

Now let’s see how we can sort by more than one column. You can pass multiple arguments to order_by(). The following example sorts by username in ascending order first, and then by created_at in descending order:

from sqlalchemy import desc

query = session.query(User).order_by(User.username, desc(User.created_at))

Sorting with Nulls

When sorting query results, handling NULL values properly is crucial. SQLAlchemy allows you to specify how NULL values are treated in your sort order using functions like nullsfirst() and nullslast().

from sqlalchemy import nullsfirst

query = session.query(User).order_by(nullsfirst(User.signup_confirmation_date), User.username)

Using Case Statements in Sorts

SQLAlchemy allows you to use case statements within your order by clause through the case() construct. For instance, to sort users based on whether they have a specific role, and then by username:

from sqlalchemy import case

sort_case = case([
    (User.role == 'admin', 0),
    (User.role == 'editor', 1)
], else_=2)

query = session.query(User).order_by(sort_case, User.username)

Dynamic Sorting with Function Expressions

For more complex sorting, you might want to use a function expression. The following example uses the func namespace to sort users based on the length of their usernames:

from sqlalchemy.sql import func

query = session.query(User).order_by(func.length(User.username).desc())

Chainable and Compound Ordering

In scenarios where the sorting order is complex or depends on runtime conditions, SQLAlchemy allows for chainable order_by clauses. You can set up multiple sorting criteria and then conditionally apply them as needed. For the truly adventurous, you can even compose order_by clauses using compound expressions:

order_by_clause = asc(User.username)
if condition:
    order_by_clause = desc(User.username).nullslast()

query = session.query(User).order_by(order_by_clause)

Concluding Thoughts

This tutorial aimed to demystify multi-column sorting in SQLAlchemy, offering various examples showing increasingly complex scenarios. Whether you’re sorting alphabetically, chronologically, or based on calculated fields, SQLAlchemy gives you the tools to order your results exactly how you need them.