我正在尝试编写一个查询来比较当前给定计算机的平均连接数与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;
编写这种类型的查询的最佳方法是,窗函数方法是否有意义,还是有更优化的方法来处理大型表的情况?
答案 0 :(得分:6)
您的部分问题是您选择了一个糟糕的列名"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模式下允许。它们表示框架的开始或结束 当前行之前或之后的许多行的行。价值必须是 不包含任何变量的整数表达式,聚合 功能或窗口功能。
相反,我只是在输入行上使用带有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;
答案 1 :(得分:4)
要得到......
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中。