Использование COUNT (*) OVER () в текущем запросе с SQLAlchemy поверх PostgreSQL

1

В прототипном приложении, использующем Python и SQLAlchemy с базой данных PostgreSQL, я имею следующую схему (выдержку):

class Guest(Base):
    __tablename__ = 'guest'
    id = Column(Integer, primary_key=True)
    name = Column(String(50))
    surname = Column(String(50))
    email = Column(String(255))
    [..]
    deleted = Column(Date, default=None)

Я хочу построить запрос, используя SQLAlchemy, который извлекает список гостей, которые будут отображаться в бэк-офисе.

Для реализации разбиения на страницы я буду использовать LIMIT и OFFSET, а также COUNT (*) OVER(), чтобы получить общее количество записей при выполнении запроса (не с другим запросом).

Примером SQL-запроса может быть:

  SELECT id, name, surname, email,
       COUNT(*) OVER() AS total
    FROM guest
   WHERE (deleted IS NULL)
ORDER BY id ASC
   LIMIT 50
  OFFSET 0

Если бы я должен был построить запрос с помощью SQLAlchemy, я мог бы сделать что-то вроде:

query = session.query(Guest)
query = query.filter(Login.deleted == None)
query = query.order_by(Guest.id.asc())
query = query.offset(0)
query = query.limit(50)
result = query.all()

И если бы я хотел считать все строки в таблице гостей, я мог бы сделать что-то вроде этого:

from sqlalchemy import func
query = session.query(func.count(Guest.id))
query = query.filter(Login.deleted == None)
result = query.scalar()

Теперь вопрос, который я задаю, заключается в том, как выполнить один единственный запрос, используя SQLAlchemy, аналогично тому, как это было выше, что убивает двух птиц одним камнем (возвращает первые 50 строк и количество полных строк для создания ссылок на страницы, все в одном запросе).

Интересным битом является использование оконных функций в PostgreSQL, что позволяет вышеназванное поведение, тем самым избавляя вас от необходимости запрашивать дважды, но только один раз.

Является ли это возможным?

Заранее спасибо.

Теги:
sqlalchemy

2 ответа

0

Поэтому я не нашел примеров в документации SQLAlchemy, но нашел эти функции:

  • [count()][1]
  • [over()][1]
  • [label()][1]

И мне удалось совместить их, чтобы получить именно тот результат, который я искал:

from sqlalchemy import func
query = session.query(Guest, func.count(Guest.id).over().label('total'))
query = query.filter(Guest.deleted == None)
query = query.order_by(Guest.id.asc())
query = query.offset(0)
query = query.limit(50)
result = query.all()

Ура!

PS Я также нашел этот вопрос в Stack Overflow, который остался без ответа.

0

Вы можете запускать SQL непосредственно в SQLAlchemy:

engine = create_engine('postgresql://postgres:password@localhost:5432/yourdb', use_batch_mode=True)
with engine.connect() as conn, conn.begin():
    query = """
                SELECT id, name, surname, email,
                   COUNT(*) OVER() AS total
                FROM guest
                WHERE (deleted IS NULL)
                ORDER BY id ASC
                LIMIT 50
                OFFSET 0;"""
    cur = conn.execute(query)
    result = cur.fetchall()

Ещё вопросы

Сообщество Overcoder
Наверх
Меню