在多个分组依据中重复使用同一查询?

时间:2019-06-08 17:55:21

标签: python sql postgresql sqlalchemy database-performance

我有一个与所需行匹配的数据库查询。假设(为简单起见):

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 个答案:

答案 0 :(得分:3)

  

我不希望Postgres多次运行相同的行匹配

这是GROUPING SETS功能背后的动机之一。试试这个模型:

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

答案 1 :(得分:2)

用户Abelisto的注释和其他答案都具有在1个单个查询中为多个字段生成直方图所需的正确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