Метод having класса Select
Метод having класса Select добавляет
условие фильтрации к результатам группировки.
Он работает аналогично оператору HAVING
в SQL и применяется после group_by.
Первым параметром метод принимает условие
в виде выражения SQLAlchemy, например
func.count() > 5.
Синтаксис
select(...).group_by(...).having(condition)
Пример
Давайте создадим таблицу статей и сгруппируем их по статусу, оставив только те группы, где количество статей больше одной:
from sqlalchemy import create_engine, select, func, String
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] = mapped_column(String(50))
status: Mapped[str] = mapped_column(String(20))
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
session.add_all([
Article(title='article 1', status='published'),
Article(title='article 2', status='published'),
Article(title='article 3', status='draft'),
])
session.commit()
stmt = (
select(Article.status, func.count(Article.id))
.group_by(Article.status)
.having(func.count(Article.id) > 1)
)
res = session.execute(stmt).all()
print(res)
Результат выполнения кода:
[('published', 2)]
Итоговый SQL запрос:
SELECT articles.status, count(articles.id) AS count_1
FROM articles
GROUP BY articles.status
HAVING count(articles.id) > 1
Пример
Давайте используем несколько условий в having
через логические операторы:
from sqlalchemy import create_engine, select, func, String, and_
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] = mapped_column(String(50))
status: Mapped[str] = mapped_column(String(20))
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', status='published', num=10),
Article(title='article 2', status='published', num=20),
Article(title='article 3', status='draft', num=30),
])
session.commit()
stmt = (
select(Article.status, func.sum(Article.num))
.group_by(Article.status)
.having(and_(
func.count(Article.id) >= 1,
func.sum(Article.num) > 15
))
)
res = session.execute(stmt).all()
print(res)
Результат выполнения кода:
[('draft', 30), ('published', 30)]
Итоговый SQL запрос:
SELECT articles.status, sum(articles.num) AS sum_1
FROM articles
GROUP BY articles.status
HAVING count(articles.id) >= 1 AND sum(articles.num) > 15