Explain Codes LogoExplain Codes Logo

How to execute "left outer join" in SqlAlchemy

sql
left-outer-join
sqlalchemy
database-queries
Anton ShumikhinbyAnton Shumikhin·Aug 22, 2024
TLDR

Create a Left Outer Join in SqlAlchemy by applying isouter=True in the join() function. Example is given below:

# Users and Addresses are mapped classes, apparently on good terms :) results = session.query(Users).join(Addresses, Users.id == Addresses.user_id, isouter=True).all()

This fetches all Users and related Addresses. Even the Users who prefer to live in the wild are included.

For ORM, there's outerjoin which is more than happy to join the party:

results = session.query(Users).outerjoin(Users.addresses).all()

Elaborating Key Components

Let's dive deeper and understand advanced scenarios.

Setting up Relationships

Defining relationships between models is key:

# The User and Address models are now in a relationship; it's complicated class User(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) addresses = relationship("Address", backref="user") class Address(Base): __tablename__ = 'addresses' id = Column(Integer, primary_key=True) user_id = Column(Integer, ForeignKey('users.id'))

backref opens a two-way street, Users can visit Addresses and vice versa.

Manage Specific Join Conditions

If a relationship is undefined or you need a special join condition, outerjoin() plays well:

# You can play cupid by setting your own match conditions --> results = session.query(Users).outerjoin(Addresses, Users.id == Addresses.user_id).all()

Removing Unsuccessful Joins

To showcase the essence of SQL 'LEFT OUTER JOIN' and include only successful pairs, apply a filter:

# Exclude the cold, unmatched ones! It's like SQL Tinder! results = session.query(Users).outerjoin(Addresses).filter(Addresses.user_id != None).all()

Mastering Left Outer Join Results

What's the use of a join if you don't know what to expect? Let's unfold the mysteries of LEFT OUTER JOIN.

Handling Null Foreign Keys

How would you get those Users who love solitude? Listen to null foreign keys:

# Bringing out the "Forever alone" Users in the results set. results = session.query(Users).outerjoin(Addresses).filter(Addresses.id == None).all()

Picking Specific Fields

Desire only the chosen fields from the tables:

# Only pick the apples you love results = session.query(Users.name, Addresses.description).outerjoin(Addresses).all()

Tuning the Result Set

A customized left outer join for special needs:

# Custom results, this is where SQL doesn't feel out of the box! results = session.query(Users).outerjoin(Addresses, and_(Users.id == Addresses.user_id, Addresses.type == 'home')).all()

Dodge Traps and Pitfalls

Outer joins in SQLAlchemy can be a slippery snake, but not anymore. Here's your survival kit.

Avoid Blurred Relationships

Be unambiguous about paths when multiple foreign keys point to the same table:

# Clarity is the key to success! And yes, it also avoids bugs. results = session.query(Users).outerjoin(Users.addresses) # 'addresses' is a cute attribute on the 'User' model.

Use of Aliases

Use aliases for clarity when Sakila asks you to join the same table multiple times:

# Aliasing: Fight duplicates with elegance address_alias = aliased(Address) results = session.query(User).outerjoin(address_alias, isouter=True).all()

By being unambiguous and explicit, you keep SURPRISE bugs at bay.