【问题标题】:Group PostgreSQL data to have no more than N values in output将 PostgreSQL 数据分组以在输出中包含不超过 N 个值
【发布时间】:2018-01-12 07:12:28
【问题描述】:

我需要快速加载图表数据。数据位于日期 Y 表中:

CREATE TABLE (
    id serial primary key,
    date timestamp not null,
    y1 double precision,
    y2 double precision,
    y3 double precision,
    y4 double precision,
    ....................
    yN double precision
);

为了简化这个问题,假设我只加载日期(X 轴)和 Y1(Y 轴)。

图表包含水平 N 个点并具有可变缩放。 X 轴包含从 mindate 到 maxdate 的点。 mindate 和 maxdate 的值取决于当前的缩放和平移位置。

为了快速加载数据,我需要使用任何聚合函数(MIN、MAX、AVG)执行动态数据分组,以便在从 mindate 到 maxdate 的范围内获得不超过 N 条聚合记录。

数据应按相等的时间间隔分组,即每 5 秒、每 3 分钟,具体取决于当前图表比例。

如何使用 PostgreSQL 实现这一点?

样本

select date, "1_2_pt100_x_1" from ob_data where "1_2_pt100_x_1" is not null order by date

13414 条记录:

"2016-12-08 12:13:41";44.5
"2016-12-08 12:16:42";44.7000007629395
"2016-12-08 12:19:43";44.9000015258789
"2016-12-08 12:22:44";45.2999992370606
"2016-12-08 12:25:44";45.5
"2016-12-08 12:30:11";45.9000015258789
"2016-12-08 12:33:12";45.5999984741211
"2016-12-08 12:36:12";45.9000015258789
"2016-12-08 12:39:13";46.2000007629395
"2016-12-08 12:42:14";46.5
"2016-12-08 12:45:15";46.5999984741211
"2016-12-08 12:48:15";46.9000015258789
"2016-12-08 12:51:16";47
"2016-12-08 12:54:16";47.0999984741211
"2016-12-08 12:57:17";47.4000015258789
"2016-12-08 13:00:17";47.4000015258789
"2016-12-08 13:03:18";47.7000007629395
"2016-12-08 13:06:18";47.7999992370606
"2016-12-08 13:09:19";47.7999992370606
"2016-12-08 13:12:19";47.7999992370606
"2016-12-08 13:15:20";48.0999984741211
"2016-12-08 13:18:20";48.0999984741211
"2016-12-08 13:21:21";48
"2016-12-08 13:24:21";48.4000015258789
"2016-12-08 13:27:22";48.2999992370606
"2016-12-08 13:30:22";48.2000007629395
"2016-12-09 08:58:54";20.2999992370606
"2016-12-09 09:01:55";20.3999996185303
"2016-12-09 09:04:55";20.6000003814697
"2016-12-09 09:07:56";20.6000003814697
"2016-12-09 09:10:56";20.8999996185303
"2016-12-09 09:13:57";20.7000007629395
"2016-12-09 09:16:57";21.2999992370606
"2016-12-09 09:19:58";21.5
"2016-12-09 09:22:58";22
"2016-12-09 09:25:59";22.2000007629395
"2016-12-09 09:28:59";22.5
"2016-12-09 09:32:00";22.8999996185303
"2016-12-09 09:35:00";23.1000003814697
"2016-12-09 09:38:01";23.2999992370606
"2016-12-09 09:41:01";23.6000003814697
"2016-12-09 09:44:02";24.1000003814697
"2016-12-09 09:47:02";24.2999992370606
"2016-12-09 09:50:03";24.6000003814697
"2016-12-09 09:53:03";24.7999992370606
"2016-12-09 09:56:04";25.2000007629395
"2016-12-09 09:59:04";25.2999992370606
"2016-12-09 10:02:05";25.7000007629395
"2016-12-09 10:05:05";25.8999996185303
"2016-12-09 10:08:06";25.8999996185303
"2016-12-09 10:11:06";26.2999992370606
"2016-12-09 10:14:07";26.3999996185303
"2016-12-09 10:17:07";26.7999992370606

预期输出

对于前 6 行,比例因子为 2,使用平均函数:

"2016-12-08 12:13:41";44,6000003814698
"2016-12-08 12:19:43";45,1000003814698
"2016-12-08 12:25:44";45,7000007629395

(我是自己用计算器算出来的,所以不要问我对应的SQL查询)。

为每个汇总结果取 2 行实际上并不是正确的方法。 mindate 和 maxdate 之间的整个数据空间应该被分成 N 个相等的间隔,每个间隔应该被聚合。作为日期的汇总值,我应该取每个间隔的第一个日期。

【问题讨论】:

标签: sql postgresql grouping aggregate-functions


【解决方案1】:

我导入了你的数据:

create table so6 (d timestamp,f float);
copy so6 from stdin delimiter ',';

这里ntile(27) 意味着你必须将 53 除以 2 才能得到 27 - 如果你想每两行聚合,如果你想要每五行,那就是 ntile(11):

with p as (
         select *, ntile(27) over(order by d) n
         from so6
         order by d
) select distinct min(d) over (partition by n),
         avg(f) over (partition by n)
from p
order by min;

         min         |       avg
---------------------+------------------
 2016-12-08 12:13:41 | 44.6000003814698
 2016-12-08 12:19:43 | 45.1000003814697
 2016-12-08 12:25:44 | 45.7000007629395
 2016-12-08 12:33:12 |            45.75
 2016-12-08 12:39:13 | 46.3500003814698
 2016-12-08 12:45:15 |            46.75
 2016-12-08 12:51:16 | 47.0499992370605
 2016-12-08 12:57:17 | 47.4000015258789
 2016-12-08 13:03:18 |            47.75
 2016-12-08 13:09:19 | 47.7999992370606
 2016-12-08 13:15:20 | 48.0999984741211
 2016-12-08 13:21:21 | 48.2000007629395
 2016-12-08 13:27:22 |            48.25
 2016-12-09 08:58:54 | 20.3499994277954
 2016-12-09 09:04:55 | 20.6000003814697
 2016-12-09 09:10:56 | 20.8000001907349
 2016-12-09 09:16:57 | 21.3999996185303
 2016-12-09 09:22:58 | 22.1000003814697
 2016-12-09 09:28:59 | 22.6999998092652
 2016-12-09 09:35:00 | 23.1999998092652
 2016-12-09 09:41:01 | 23.8500003814697
 2016-12-09 09:47:02 | 24.4499998092652
 2016-12-09 09:53:03 |               25
 2016-12-09 09:59:04 |             25.5
 2016-12-09 10:05:05 | 25.8999996185303
 2016-12-09 10:11:06 | 26.3499994277954
 2016-12-09 10:17:07 | 26.7999992370606
(27 rows)

【讨论】:

  • 非常感谢!实际上我并不完全理解它是如何工作的,但它确实有效。无论向表中添加了多少列,是否可以对除“d”之外的所有数据列执行自动 AVG? (相当于 SELECT *)
  • 对不起 - 我不明白 :) 很难看出你想要什么,除非你像最初的问题那样放置样本数据
  • 我的意思是 SELECT * FROM 查询不需要提及所有字段,但对于聚合查询,可能没有等效项。
  • 好吧 - 当你聚合时,你会围绕一些列进行聚合,所以你必须指定它们
猜你喜欢
  • 2017-07-05
  • 1970-01-01
  • 2021-12-31
  • 1970-01-01
  • 2023-03-15
  • 2022-07-22
  • 2014-02-05
  • 1970-01-01
  • 2019-09-26
相关资源
最近更新 更多