Метод join класса Select
Метод join класса Select выполняет
соединение таблиц в SQL-запросе. Первым параметром
метод принимает целевую таблицу или модель, к которой
нужно присоединиться. Вторым необязательным параметром
передается условие соединения onclause. Если условие
не указано, SQLAlchemy пытается определить связь между
таблицами автоматически по внешним ключам. Также можно
передать флаг isouter для выполнения внешнего
соединения и full для полного соединения.
Синтаксис
select(...).join(target, [onclause], [isouter], [full])
Пример
Давайте создадим две связанные модели и выполним простое внутреннее соединение:
from sqlalchemy import create_engine, select, ForeignKey
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = 'users'
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str]
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
user_id: Mapped[int] = mapped_column(ForeignKey('users.id'))
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
session.add(User(id=1, name='user'))
session.add(Article(id=1, title='article', user_id=1))
session.commit()
stmt = select(Article.title, User.name).join(User)
res = session.execute(stmt).all()
print(res)
Результат выполнения кода:
[('article', 'user')]
Пример
Давайте укажем условие соединения явно через
параметр onclause:
from sqlalchemy import create_engine, select, ForeignKey
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = 'users'
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str]
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
user_id: Mapped[int] = mapped_column(ForeignKey('users.id'))
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
session.add(User(id=1, name='user'))
session.add(Article(id=1, title='article', user_id=1))
session.commit()
stmt = select(Article.title, User.name).join(
User, Article.user_id == User.id
)
res = session.execute(stmt).all()
print(res)
Результат выполнения кода:
[('article', 'user')]
Пример
Давайте выполним внешнее соединение с флагом
isouter, чтобы получить все статьи даже
без связанного пользователя:
from sqlalchemy import create_engine, select, ForeignKey
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = 'users'
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str]
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
user_id: Mapped[int] = mapped_column(ForeignKey('users.id'), nullable=True)
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
session.add(User(id=1, name='user'))
session.add(Article(id=1, title='article', user_id=1))
session.add(Article(id=2, title='article 2', user_id=None))
session.commit()
stmt = select(Article.title, User.name).join(User, isouter=True)
res = session.execute(stmt).all()
print(res)
Результат выполнения кода:
[('article', 'user'), ('article 2', None)]
Итоговый SQL запрос:
SELECT articles.title, users.name
FROM articles
LEFT OUTER JOIN users ON users.id = articles.user_id