2012-11-13 36 views
3

我正在嘗試編寫一個查詢來比較給定計算機今天的平均連接數與7至14天之前的平均連接數。我想這最好是通過窗口函數來處理,但我無法獲得日期正確的語法。PostgreSQL中的窗口函數追蹤日期

假設我有一個IP地址和連接記錄表稱爲iptable與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; 

什麼是寫這種類型的查詢沒有窗函數的方法是有意義的最好辦法還是有更優化的方式來處理大表的情況?

+1

請顯示所有問題,你的PostgreSQL版本,和錯誤消息的確切文本。 –

回答

6

問題的一部分是,您選擇了一個可怕的列名稱,"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... 
                  ^

這表明你想讓它做什麼當前窗口功能的實現不會做。可悲的是。

The value PRECEDING and value FOLLOWING cases are currently only allowed in ROWS mode. They indicate that the frame starts or ends with the row that many rows before or after the current row. value must be an integer expression not containing any variables, aggregate functions, or window functions.

相反,我只是使用普通的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; 
4

要獲得...

the number of average connections between 7 and 14 days ago

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中。