Повторно использовать один и тот же запрос в нескольких группах? - PullRequest
1 голос
/ 08 июня 2019

У меня есть запрос к БД, который соответствует желаемым строкам.Допустим (для простоты):

select * from stats where id in (1, 2);

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

-- `stats.status` is one such column
select status, count(*) from stats where id in (1, 2) group by 1 order by 2 desc;

-- `stats.category` is another column
select category, count(*) from stats where id in (1, 2) group by 1 order by 2 desc;

-- etc.

Есть ли способ повторно использовать тот же базовый запрос в SqlAlchemy?Необработанный SQL тоже работает.

Или, что еще лучше, вернуть все гистограммы за одну команду?

Меня больше всего интересует производительность, потому что я не хочуPostgres запускает одно и то же сопоставление строк много раз, по одному разу для каждого столбца, снова и снова.Единственное изменение - какой столбец используется для группировки гистограмм.В противном случае это тот же набор строк.

Ответы [ 2 ]

3 голосов
/ 08 июня 2019

Я не хочу, чтобы Postgres запускал одно и то же сопоставление строк много раз

Это одна из причин, стоящих за функциональностью GROUPING SETS . Попробуйте эту модель:

SELECT category, status, count(*)
FROM stats where id in (1,2)
GROUP BY grouping sets ((category),(status));
2 голосов
/ 09 июня 2019

Пользователь Комментарий Абелисто и другой ответ имеют правильный sql, необходимый для создания гистограммы для нескольких полей в одном запросе.

Единственное редактирование, которое я предложил бы для их усилий, - это добавить предложение ORDER BY, поскольку из попыток ОП видно, что в верхней части результата нужны более частые метки.Вы можете обнаружить, что сортировка результатов в python, а не в базе данных проще.В этом случае не обращайте внимания на сложность, приведенную к порядку с помощью предложения.

Таким образом, измененный запрос будет:

SELECT category, status, count(*)
FROM stats
WHERE id IN (1, 2)
GROUP BY GROUPING SETS ( 
  (category), (status) 
)
ORDER BY 
  GROUPING(category, status), 3 DESC

Также можно выразить тот же запрос с помощью sqlalchemy.

from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()
class Stats(Base):
    __tablename__ = 'stats'
    id = Column(Integer, primary_key=True)
    category = Column(Text)
    status = Column(Text)

stmt = select(
    [Stats.category, Stats.status, func.count(1)]
).where(
    Stats.id.in_([1, 2])
).group_by(
    func.grouping_sets(tuple_(Stats.category), 
                       tuple_(Stats.status))
).order_by(
    func.grouping(Stats.category, Stats.status),
    func.count(1).desc()
)

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

print(stmt.compile(compile_kwargs={'literal_binds': True}))
# outputs:
SELECT stats.category, stats.status, count(1) AS count_1 
FROM stats 
WHERE stats.id IN (1, 2) 
GROUP BY GROUPING SETS((stats.category), (stats.status)) 
ORDER BY grouping(stats.category, stats.status), count(1) DESC
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...