跨多个groupby重用同一查询?

2024-03-29 06:41:43 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个匹配所需行的DB查询。让我们说(为了简单起见):

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多次运行同一行匹配,每列一次,一遍又一遍。唯一的变化是哪个列用于直方图分组。否则就是同一组行。你知道吗


Tags: infromidbyisstatsstatuscount
2条回答

I don't want Postgres to run the same row-matching many times

这就是GROUPING SETS功能背后的动机之一。尝试此模式:

SELECT category, status, count(*)
FROM stats where id in (1,2)
GROUP BY grouping sets ((category),(status));

用户Abelisto的注释和另一个答案都具有在一个查询中为多个字段生成直方图所需的正确sql。你知道吗

对于他们的努力,我建议的唯一编辑是添加一个ORDER BY子句,因为从OP的尝试来看,在结果的顶部需要更频繁的标签。您可能会发现,用python排序结果比在数据库中排序更简单。在这种情况下,忽略order by子句带来的复杂性。你知道吗

因此,修改后的查询将是:

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

相关问题 更多 >