Функция within_group
Функция within_group создает агрегатную функцию
с предложением WITHIN GROUP, которое задает порядок
сортировки значений внутри агрегата. Первым параметром
функция принимает агрегатную функцию, например
func.percentile_cont или func.array_agg,
а последующими параметрами - выражения для сортировки.
Предложение WITHIN GROUP поддерживается не всеми
СУБД, наиболее полно оно реализовано в PostgreSQL.
Синтаксис
within_group(func, *order_by)
Пример
Давайте создадим упорядоченную агрегатную функцию
для вычисления медианы столбца num:
from sqlalchemy import create_engine, select, func
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]
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', num=10),
Article(title='article 2', num=20),
Article(title='article 3', num=30),
])
session.commit()
stmt = select(
func.percentile_cont(0.5).within_group(Article.num)
)
res = session.execute(stmt).scalar()
print(res)
Результат выполнения кода:
20.0
Пример
Давайте зададим сортировку по убыванию с помощью
функции desc:
from sqlalchemy import create_engine, select, func, desc
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]
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', num=10),
Article(title='article 2', num=20),
Article(title='article 3', num=30),
])
session.commit()
stmt = select(
func.percentile_cont(0.5).within_group(desc(Article.num))
)
res = session.execute(stmt).scalar()
print(res)
Результат выполнения кода:
20.0
Пример
Давайте посмотрим итоговый SQL-запрос, который
генерирует функция within_group:
from sqlalchemy import create_engine, select, func
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
num: Mapped[int]
stmt = select(
func.percentile_cont(0.5).within_group(Article.num)
)
print(stmt)
Итоговый SQL запрос:
SELECT percentile_cont(:percentile_cont_1) WITHIN GROUP (ORDER BY articles.num) AS anon_1
FROM articles