PostgreSQL 中的窗口函数尾随日期

Posted

技术标签:

【中文标题】PostgreSQL 中的窗口函数尾随日期【英文标题】:Window function trailing dates in PostgreSQL 【发布时间】:2012-11-13 21:07:50 【问题描述】:

我正在尝试编写一个查询来比较给定计算机今天的平均连接数与 7 到 14 天前的平均连接数。我认为这最好由窗口函数处理,但我无法获得正确的日期语法。

假设我有一个名为 iptable 的 IP 地址和连接记录表,其中包含 soucreip、destinationip、timestamp 作为列。这是我在前 7 天窗口中尝试的查询,以获取每个 sourceip 的计数:

select 
  sourceip, 
  destinationip, 
  timestamp, 
  count(*) OVER (PARTITION BY sourceip order by timestamp
                 RANGE BETWEEN now() - '7 day'::Interval PRECEDING
                               now() - '14 day'::Interval FOLLOWING)
from
 iptable;

编写此类查询的最佳方法是什么?窗口函数方法是否有意义,或者是否有更优化的方法来处理大型表的情况?

【问题讨论】:

请在所有问题中显示您的 PostgreSQL 版本,以及错误消息的确切文本。 【参考方案1】:

部分问题是您选择了一个糟糕的列名"timestamp"timestamp 是内置数据类型的名称,因此要将其用作列名,您必须在任何地方使用"double quote"

不过,这还不是全部。您的窗口函数语法错误。见window function syntax。你忘了AND;是RANGE BETWEEN .. PRECEDING AND ... FOLLOWING

此外,虽然这不是问题的原因,但您应该使用 SQL 标准 current_timestamp 而不是 now()

这会让你遇到一个新错误:

CREATE TABLE iptable ( sourceip cidr, destinationip cidr, "timestamp" timestamptz);

regress=> select 
  sourceip, 
  destinationip, 
  timestamp, 
  count(*) OVER (PARTITION BY sourceip order by "timestamp" RANGE BETWEEN current_timestamp - '7 day'::Interval PRECEDING AND current_timestamp - '14 day'::Interval FOLLOWING)

from
 iptable;
ERROR:  RANGE PRECEDING is only supported with UNBOUNDED
LINE 5: ... OVER (PARTITION BY sourceip order by "timestamp" RANGE BETW...
                                                             ^

这表明当前的窗口函数实现不会做你想让它做的事情。很遗憾。

值 PRECEDING 和值 FOLLOWING 的情况目前只有 在 ROWS 模式下允许。它们表明帧以 当前行之前或之后的行数。值必须是 一个不包含任何变量的整数表达式,聚合 函数或窗口函数。

我只会在输入行上使用带有 WHERE 过滤器的普通 GROUP BY

select 
  sourceip,
  count(sourceip) AS n_conns_7_to_14_days_ago
from
 iptable
WHERE age("timestamp") BETWEEN INTERVAL '7' DAY AND INTERVAL '14' DAY
GROUP BY sourceip;

【讨论】:

【参考方案2】:

为了得到……

7 天到 14 天前的平均连接数

SELECT sourceip, destinationip, timestamp, count(*) AS ct
FROM   iptable
WHERE  "timestamp" BETWEEN now() - '14 day'::interval
                   AND     now() -  '7 day'::interval
GROUP BY 1,2,3;

只需使用简单的聚合函数即可。 并且不要使用timestamp 作为列名。它是 SQL 标准中的 protected word,部分保留在 PostgreSQL 中。

【讨论】:

以上是关于PostgreSQL 中的窗口函数尾随日期的主要内容,如果未能解决你的问题,请参考以下文章

PostgreSQL 中的 PERCENTILE_DISC() 作为窗口函数

带有 LIMIT 的 PostgreSQL 窗口函数

使用窗口函数确定 PostgreSQL 中的 30 天运行计数

PostgreSQL:json中的词汇概述,窗口函数......递归?

在窗口函数 postgresql 中选择条件

PostgreSQL中group by中的窗口函数