5

我在 PostgreSQL 中有一张这样的表。我想根据 ID(这是主键)为每 16 条记录执行聚合函数,如平均值和最大值。例如,我必须计算前 16 条记录和后 16 条记录的平均值,依此类推。

+-----+-------------
| ID  |  rainfall  |
+-----+----------- |
|  1  |  110.2     |
|  2  |  56.6      |
|  3  |  65.6      |
|  4  |  75.9      |
+-----+------------
4

2 回答 2

12

想到的第一种方法是使用row_number()注释表,然后按 16 行的块分组。

SELECT min(id) as first_id, max(id) AS last_id, avg(rainfall) AS avg_this_16
FROM (
  SELECT id, rainfall, row_number() OVER (order by id) AS n
  FROM the_table
) x(id,rainfall,n)
GROUP BY n/16
ORDER BY n/16;

请注意,这不一定包括最后一组的 16 个样本。

或者,您可以通过用作窗口函数来计算运行平均值:avg()

SELECT id, avg(rainfall) OVER (ORDER BY id ROWS 15 PRECEDING)
FROM the_table;

...可能用行号注释它并选择你想要的:

SELECT id AS greatest_id_in_group, avg_last_16_inclusive FROM (
  SELECT
    id, 
    avg(rainfall) OVER (ORDER BY id ROWS 15 PRECEDING) AS avg_last_16_inclusive,
    row_number() OVER (ORDER BY id) AS n
  FROM the_table
) x WHERE n % 16 = 0;

这将忽略最后的 n<16 个样本,而不是为它们返回一行。

请注意,我假设不保证 ID 是连续的。如果它们没有间隙,则group by id/16可以避免使用窗口功能。

于 2012-10-27T10:08:32.133 回答
0

迟到的答案,但无论如何供参考

因为ID据说是连续的和无间隙的,那么这将非常简单

SELECT avg(rainfall),string_agg(id::text, ',')
FROM the_table
GROUP BY (id - 1) / 16;

注意 使(id - 1)分组从 0 到 15,否则第一组可能会失相

PS:@Craig Ringer 在回答结束时给出了提示,但没有发布为代码

请注意,我假设不保证 ID 是连续的。如果它们没有间隙,您可以按 id/16 分组并避免使用窗口功能。

于 2018-02-13T14:12:51.473 回答