标准的 GROUP BY 查询将为您提供大部分帮助:
SELECT
user_id,
type_of_place,
avg(money_earned) AS avg,
stddev(money_earned) AS stddev
FROM
earnings -- I'm not sure what your data table is called...
GROUP BY
user_id,
type_of_place
这留下了top5_places
和mode
列。这些也是聚合,但不是标准 PostgreSQL 安装中定义的聚合。幸运的是,您可以添加它们。
这是一个讨论如何定义mode
聚合函数的页面: http ://wiki.postgresql.org/wiki/Aggregate_Mode
一旦你有了一个mode
聚合函数,假设time
是某种时间戳,你将添加到选择列表中的表达式将是:
SELECT
...
mode(extract(hour FROM time)) AS mode -- Add this expression
FROM
...
假设按钱订购
对于top5_places
,有几种方法,但最快的可能是使用 PostgreSQL 的内置array_agg
函数,并取前 5 个元素:
SELECT
...
(array_agg(place ORDER BY money_earned DESC))[1:5] AS top5_places -- Add this expression
FROM
...
一种替代方法是定义另一个名为 (for instance) 的聚合top5
,它执行相同的功能。如果每个用户/地点类型的组合有许多不同的地点,这可能会更有效,因为它可以在前 5 个之后停止累积,而上面的表达式通常会构建所有地点的完整数组,然后截断到第一个5.
这假设一个地方对于每个用户/类型组合都有一个唯一的收入条目。 如果一个地方可以出现多次,并且您想sum(money_earned)
为每个地方排序,那么您需要使用如下示例中的子查询...
按数量排序
好的,所以这些地方应该按照它们出现的频率来排序。这是一种使用几个子查询的快速方法——将其作为表达式添加到上述查询的选择子句中:
(SELECT
(array_agg(place ORDER BY cnt DESC))[1:5]
FROM
(SELECT place, count(*) FROM earnings AS t2
WHERE t2.user_id = earnings.user_id AND t2.type_of_place = earnings.type_of_place
GROUP BY place) AS s (place, cnt)
) AS top5_places
调用的内部子查询s
为每个用户/类型组合计算一个表place
,以及它出现的次数(我称之为cnt
)。array_agg
然后按该计数的降序将这些输入。
我怀疑可能会有更简洁(并且可能更有效)的编写方式。如果没有,那么我建议您尝试将这个复杂的表达式移动到函数或聚合中,如果可以的话......
每小时地点的直方图
我们将使用类似的表达式,它将返回按小时排序的计数数组:
(SELECT
array_agg(cnt ORDER BY hour DESC)
FROM
(SELECT extract(hour FROM time), count(*) FROM earnings AS t2
WHERE t2.user_id = earnings.user_id AND t2.type_of_place = earnings.type_of_place
GROUP BY 1) AS s (hour, cnt)
) AS hourly_histogram
(将其添加到原始查询的选择子句中。)