Postgresql 表中每3行求和一次

Postgresql 表中每3行求和一次,postgresql,sum,rows,group-by,window-functions,Postgresql,Sum,Rows,Group By,Window Functions,我有以下查询来计算每分钟的所有数据 $sql= "SELECT COUNT(*) AS count, date_trunc('minute', date) AS momento FROM p WHERE fk_id_b=$id_b GROUP BY date_trunc('minute', date) ORDER BY momento ASC"; 我需要做的是得到每行的计数和过去2分钟的计数之和 For example with the result of the $sql query ab

我有以下查询来计算每分钟的所有数据

$sql= "SELECT COUNT(*) AS count, date_trunc('minute', date) AS momento
FROM p WHERE fk_id_b=$id_b GROUP BY date_trunc('minute', date) 
ORDER BY momento ASC";
我需要做的是得到每行的计数和过去2分钟的计数之和

For example with the result of the $sql query above
|-------date---------|----count----|
|2012-06-21 05:20:00 |      12     |
|2012-06-21 05:21:00 |      14     |
|2012-06-21 05:22:00 |      10     |
|2012-06-21 05:23:00 |      20     |
|2012-06-21 05:24:00 |      25     |
|2012-06-21 05:25:00 |      30     |
|2012-06-21 05:26:00 |      10     |  

I want this result:

|-------date---------|----count----|
|2012-06-21 05:20:00 |      12     |   
|2012-06-21 05:21:00 |      26     |     12+14
|2012-06-21 05:22:00 |      36     |     12+14+10
|2012-06-21 05:23:00 |      44     |     14+10+20
|2012-06-21 05:24:00 |      55     |     10+20+25
|2012-06-21 05:25:00 |      75     |     20+25+30
|2012-06-21 05:26:00 |      65     |     25+30+10

这一点在以下情况下不太棘手:

创建表t(“日期”timestamptz,“计数”int4);
插入到t值中
('2012-06-21 05:20:00',12),
('2012-06-21 05:21:00',14),
('2012-06-21 05:22:00',10),
('2012-06-21 05:23:00',20),
('2012-06-21 05:24:00',25),
('2012-06-21 05:25:00',30),
('2012-06-21 05:26:00',10);
选择*,
“计数”
+合并(滞后(“计数”,1)超过(按“日期”排序),0)
+合并(滞后(“计数”,2)超过(按“日期”排序),0)为“总计”
从t;
  • 我双引号引用了
    date
    count
    列,因为它们是保留字
  • lag(field,distance)
    给出了
    field
    distance
    行与当前行之间的值,因此第一个函数给出了前一行的值,第二个调用给出了前一行的值
  • coalesce()
    需要避免
    NULL
    来自
    lag()
    函数的结果(对于查询中的第一行,没有“previous”一行,因此它是
    NULL
    ),否则
    总计也将是
    NULL
  • 大部分时间都是这样。但我的抱怨比评论中的要多

  • 根本不要使用诸如
    date
    count
    作为标识符。PostgreSQL允许这两个特定的关键字作为标识符,而不是每个SQL标准。但这仍然是一种坏习惯。您可以使用双引号内的任何内容作为标识符,即使是
    “DELETE FROM tbl;”
    ,也不是一个好主意。除此之外,
    时间戳的名称
    “date”
    还有误导性

  • 错误的数据类型。示例显示,而不是
    timestamptz
    。在这里没有区别,但仍然有误导性

  • 您不需要
    COALESCE()
    。使用,您可以提供默认值作为第三个参数:

  • 基于此设置:

    CREATE TABLE tbl (ts timestamp, ct int4);
    INSERT INTO tbl VALUES
      ('2012-06-21 05:20:00', 12)
    , ('2012-06-21 05:21:00', 14)
    , ('2012-06-21 05:22:00', 10)
    , ('2012-06-21 05:23:00', 20)
    , ('2012-06-21 05:24:00', 25)
    , ('2012-06-21 05:25:00', 30)
    , ('2012-06-21 05:26:00', 10);
    
    查询:

    SELECT ts, ct + lag(ct, 1, 0) OVER (ORDER BY ts)
                  + lag(ct, 2, 0) OVER (ORDER BY ts) AS total
    FROM   tbl;
    

    更好但:使用单个
    sum()
    作为窗口聚合函数,并使用:

    同样的结果。
    相关的:


    对于当前行和前N行的值之和,这里有一个更通用的解决方案(在您的例子中,N=2)

    您可以在0和“无界”之间更改N。这种方法让你们有机会在你们的应用程序中有一个参数“过去N分钟的计数”。此外,如果超出范围,则无需处理默认值


    您可以在PostgreSQL文档()中找到更多关于这方面的信息。

    SQL非常棘手。你的申请不能完成这项工作吗?无论如何,您都必须获取行,并且您可以在同一个循环中这样做。@Parth Bhatt:您批准的编辑显然是在问一个不同的问题。请不要批准这样的编辑。@interjay:对不起,我弄错了,我解释错了。太好了!我喜欢窗口函数的概念,但总是忘记使用它们。对正确的解决方案投赞成票:-)+1。我写了一个答案,因为注释是不够的。默认值为
    lag
    /
    lead
    是个不错的选择!
    SELECT ts, sum(ct) OVER (ORDER BY ts ROWS BETWEEN 2 PRECEDING AND CURRENT ROW)
    FROM   tbl;
    
    SELECT "date", 
    sum("count") OVER (order by "date" ROWS BETWEEN 2 preceding AND current row)
    FROM t
    ORDER BY "date";