Метод lateral класса Select
Метод lateral класса Select
превращает обычный подзапрос в
LATERAL-подзапрос. Такой подзапрос
вычисляется для каждой строки внешнего
запроса и может ссылаться на таблицы,
указанные в предложении FROM внешнего
запроса. Метод не принимает параметров и
возвращает новый объект Lateral,
который можно использовать в
select_from, join и других
методах. LATERAL особенно полезен, когда
нужно соединить каждую строку одной
таблицы с результатом подзапроса,
зависящего от этой строки.
Синтаксис
select(...).lateral()
Пример
Давайте создадим модель статьи и LATERAL-подзапрос, который возвращает название статьи и вычисляемое значение, зависящее от внешней таблицы:
from sqlalchemy import create_engine, select, literal_column
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
text: Mapped[str]
status: Mapped[str]
num: Mapped[int]
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
session.add_all([
Article(title='article 1', text='text 1', status='active', num=1),
Article(title='article 2', text='text 2', status='active', num=2),
])
session.commit()
subq = (
select(
Article.title,
literal_column('articles.num * 10').label('scaled'),
)
.where(Article.status == 'active')
.lateral()
)
stmt = select(subq.c.title, subq.c.scaled)
for row in session.execute(stmt):
print(row)
Результат выполнения кода:
('article 1', 10)
('article 2', 20)
Пример
Давайте применим lateral вместе с
join, чтобы соединить таблицу статей
с LATERAL-подзапросом:
from sqlalchemy import create_engine, select, literal_column
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
text: Mapped[str]
status: Mapped[str]
num: Mapped[int]
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
session.add_all([
Article(title='article 1', text='text 1', status='active', num=5),
Article(title='article 2', text='text 2', status='active', num=7),
])
session.commit()
subq = (
select(literal_column('articles.num + 100').label('total'))
.lateral()
)
stmt = select(Article.title, subq.c.total).join(subq, True)
for row in session.execute(stmt):
print(row)
Результат выполнения кода:
('article 1', 105)
('article 2', 107)
Смотрите также
-
класс
Select,
который представляет SELECT-запрос -
метод
subquery,
который превращает запрос в подзапрос -
метод
join,
который соединяет таблицы в запросе -
метод
select_from,
который задает источник данных для запроса