跨多个分组重用相同的查询?
Reuse same query across multiple group-bys?
我有一个与所需行匹配的数据库查询。让我们说(为简单起见):
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 也可以。
或者更好的是,return 所有直方图都在一个命令中?
我最感兴趣的是性能,因为我不希望 Postgres 多次 运行 同一行匹配,每列一次,一遍又一遍。唯一的变化是哪个列用于直方图分组。否则它是同一组行。
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 的评论和其他答案都具有在 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
我有一个与所需行匹配的数据库查询。让我们说(为简单起见):
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 也可以。
或者更好的是,return 所有直方图都在一个命令中?
我最感兴趣的是性能,因为我不希望 Postgres 多次 运行 同一行匹配,每列一次,一遍又一遍。唯一的变化是哪个列用于直方图分组。否则它是同一组行。
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 的评论和其他答案都具有在 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