3

我正在尝试编写一个查询来比较给定计算机今天的平均连接数与 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;

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

4

2 回答 2

7

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

不过,这还不是全部。您的窗口函数语法错误。请参阅窗口函数语法。你忘了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 模式下使用。它们指示帧以当前行之前或之后的行数开始或结束。value 必须是不包含任何变量、聚合函数或窗口函数的整数表达式。

相反,我只是在输入行上使用GROUP BY带有过滤器的普通文本。WHERE

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;
于 2012-11-14T00:37:02.010 回答
5

要得到 ...

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 标准中的受保护字,部分保留在 PostgreSQL 中。

于 2012-11-14T00:43:14.327 回答