最佳 SQL 执行多个具有不同分组依据字段的聚合函数

Optimal SQL to perform multiple aggregate functions with different group by fields

为了简化我正在处理的复杂查询,我觉得解决这个问题是关键。

我有以下table

id city Item
1 chicago 1
2 chicago 2
3 chicago 1
4 cedar 2
5 cedar 1
6 cedar 2
7 detroit 1

我试图找出按城市和项目分组的行数与每个唯一城市项目对仅按项目分组的行数的比率。

所以我想要这样的东西

City Item groupCityItemCount groupItemCount Ratio
chicago 1 2 4 2/4
chicago 2 1 3 1/3
cedar 1 1 4 1/4
cedar 2 2 3 2/3
detroit 1 1 4 1/4

这是我目前的解决方案,但它太慢了。

Select city, item, (count(*) / (select count(*) from records t2 where t1.item=t2.item)) AS pen_ratio
From records t1
Group By city, item

还用 groupBy 和 having 替换了 where,但这也很慢。

Select city, item, (count(*) / (select count(*) from records t2 group by item having t1.item=t2.item)) AS pen_ratio
From records t1
Group By city, item

(注意:我已从较小代码的解决方案中删除了 column3 和 column4)

(编辑:xQbert 和 MatBailie)

它慢是因为它使用 select 语句中的子查询分别计算每一行吗?它可能作为相关子查询运行。

如果是这种情况,如果您从连接中获取值并从那里开始可能会更快 -

Select city, t1.item, (COUNT(t1.item) / MAX(t2.it_count)) AS pen_ratio
from records t1
JOIN (SELECT item, count(item) AS it_count
      FROM records
      group by item) t2
        ON t2.item = t1.item
GROUP BY city, t1.item

更新了一些错误并包含了基于 xQbert 起点的 fiddle。我必须在 fiddle 中将 CAST 转换为浮点数,但您可能不需要根据数据类型在您的查询中进行 CAST 和使用上述查询。

我相信这符合您最初查询的意图。

https://dbfiddle.uk/?rdbms=postgres_13&fiddle=d77a715175159304b9192a16ad903347

您可以分两部分进行处理。

首先,像往常一样汇总到您感兴趣的级别。

然后,使用分析函数计算您的分区(项目,在您的情况下)的小计。

WITH
  aggregate AS
(
  SELECT
    city,
    item,
    COUNT(*) AS row_count
  FROM
    records
  GROUP BY
    city,
    item
)
SELECT
  city,
  item,
  row_count                               AS groupCityItemCount,
  SUM(row_count) OVER (PARTITION BY item) AS groupItemCount
FROM
  aggregate

Fiddle 借自 xQbert