2013-05-09 73 views
3

對不起,如果這是混亂,因爲我不是很熟悉postgresql。我有一個表格充滿了「網站」的postgres數據庫。每個站點報告約一小時一次,當它的報告,它使在此表中的條目,比如:如何從時間戳表中選擇每小時一行數據?

site |  tstamp 
-----+-------------------- 
6000 | 2013-05-09 11:53:04 
6444 | 2013-05-09 12:58:00 
6444 | 2013-05-09 13:01:08 
6000 | 2013-05-09 13:01:32 
6000 | 2013-05-09 14:05:06 
6444 | 2013-05-09 14:06:25 
6444 | 2013-05-09 14:59:58 
6000 | 2013-05-09 19:00:07 

正如你所看到的,時間戳是幾乎從來沒有在最前端,有時只有幾分鐘/秒的時間內會有兩次或更多次。此外,有些網站一次不會報告幾小時(有時)。我只想每個站點每小時選擇一個條目(儘可能接近每個小時)。我怎樣才能以有效的方式去做這件事?我還需要將此擴展到其他時間範圍(例如,每個站點每天有一個條目 - 儘可能接近午夜)。

謝謝你的任何和所有的建議。

回答

7

你可以使用DISTINCT ON

select distinct on (date_trunc('hour', tstamp)) site, tstamp 
from t 
order by date_trunc('hour', tstamp), tstamp 

小心與ORDER BY如果你關心你哪個條目。

或者,你可以使用row_number window function標記感興趣的行,然後從派生表剝離第一結果各組:

select site, tstamp 
from (
    select site, tstamp, 
      row_number() over (partition by date_trunc('hour', tstamp) order by tstamp) as r 
    from t 
) as dt 
where r = 1 

再次,你會調整ORDER BY選擇每個日期的特定的興趣行。

+1

@BLuFeNiX:這個!對於幾個小時或其他時間間隔,使用['date_trunc('hour',tstamp)'](http://www.postgresql.org/docs/current/interactive/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC)。 [Here](http://stackoverflow.com/questions/12623358/group-by-data-intervals/12624551#12624551)和[here](http://stackoverflow.com/questions/12730072/truncate-timestamp-to - 任意間隔/ 12731753#12731753)是任意間隔的相關答案。 – 2013-05-09 21:31:43

+0

@ErwinBrandstetter:我怎麼能把「小時」和「日期」混淆?奇怪的是,大腦,手指和眼睛有時生活在不同的世界。 – 2013-05-09 21:37:20

+0

@ muistooshort:謝謝!你的第一個查詢工作正常,但速度很慢。有關如何加快速度的建議?在第二個查詢中,我在row_number()上發生錯誤。此外,這個查詢最終將被分頁,這是否重要? – BLuFeNiX 2013-05-10 16:50:27

5

您正在尋找每小時最接近的值。有些是在小時之前,有些在之後。這使得這是一個棘手的問題。

首先,我們需要確定在特定小時內工作的值的範圍。爲此,我會考慮從小時15分鐘到45分鐘之後的任何事情。所以,2點的考慮時間從1點45分到2點45分(任意,但對你的數據來說似乎是合理的)。我們可以通過將時間戳改爲15分鐘來做到這一點。

其次,我們需要得到最接近小時的值。所以,我們更喜歡1:57到2:05。我們可以通過考慮(57,60 - 57,5,60 - 5)中的第一個值來做到這一點。

我們可以把這些規則轉換成SQL語句,使用row_number()

select site, tstamp, usedTimestamp 
from (select site, tstamp, 
      date_trunc('hour', tstamp + 'time 00:15') as usedTimestamp 
      row_number() over (partition by site, to_char(tstamp + time '00:15', 'YYYY-MM-DD-HH24'), 
           order by least(extract(minute from tstamp), 60 - extract(minute from tstamp)) 
           ) as seqnum 
     from t 
    ) as dt 
where seqnum = 1; 
+0

我得到row_number()的錯誤。任何方式來解決這個問題?此外,這個查詢最終將被分頁。 – BLuFeNiX 2013-05-10 16:51:51

+0

@BLuFeNiX。 。 。我修復了語法錯誤。 SQLFiddle在這裏(http://www.sqlfiddle.com/#!12/d41d8/937/0)。 – 2013-05-10 18:03:27

+0

謝謝!我會檢查出來的。 – BLuFeNiX 2013-05-10 19:38:26

1

對於你的問題的可擴展性方面。

I also will need to extend this to other time frames (like one entry per site per day

從不同組的網站ID的,並且使用(遞歸)CTE,我將建立一組由每小時每站點一個條目的(或其他指定的時間間隔),在指定的startDateTime內, EndDateTime範圍。

  SITE..THE DATE-TIME-HOUR 
      6000 12.1.2013 00:00:00 
      6000 12.1.2013 01:00:00 
      . 
      . 
      . 
      6000 12.1.2013 24:00:00    
      7000 12.1.2013 00:00:00   
      7000 12.1.2013 01:00:00 
      . 
      . 
      . 
      7000 12.1.2013 24:00:00 

那我就離開了加入該CTE對您的網站登錄網站ID,並在CTE點的時間和日誌的點在時間之間的最小差值的絕對值。

通過這種方式,您可以確保每個網站的每個網站都有一行。

P.S.對於長時間未打電話的網站,最近的電話接入時間戳會重複多次,因爲它是最近的電話接入時間戳。

相關問題