2013-06-26 86 views
35

我有一個傳感器數據表。每行都有一個傳感器ID,一個時間戳和其他字段。我想爲每個傳感器選擇帶有最新時間戳的單行,包括其他一些字段。如何爲每個鍵值選擇具有最新時間戳的行?

我認爲,解決辦法是按傳感器ID,然後才能由Max(時間戳),像這樣:

SELECT sensorID,timestamp,sensorField1,sensorField2 
FROM sensorTable 
GROUP BY sensorID 
ORDER BY max(timestamp); 

這給了我一個錯誤,指出「sensorField1必須by子句中的組或者用於彙總。「

解決此問題的正確方法是什麼?

+0

您使用的是哪種數據庫引擎? –

+0

儘管以下使用JOIN的Max(timestamp)值的答案應該可行,但如果sensorTable上有一個SensorReadingId,我會建議加入SensorReadingId。 –

回答

12

您只能選擇組中或在聚合函數中使用的列。您可以使用連接得到這個工作

select s1.* 
from sensorTable s1 
inner join 
(
    SELECT sensorID, max(timestamp) as mts 
    FROM sensorTable 
    GROUP BY sensorID 
) s2 on s2.sensorID = s1.sensorID and s1.timestamp = s2.mts 
+0

...或'select * from sensorTable其中(sensorID,timestamp)in(選擇sensorID,max(timestamp)from sensorTable group by sensorID)'。 – Arjan

+0

我認爲「LEFT JOIN」也適用,不僅僅是「INNER JOIN」;和一部分「和s1.timestamp = s2.mts」不是nessesary恕我直言。然而,我建議在兩個字段上創建索引:sensorID + timestamp - 查詢速度提高很多! – Igor

3
WITH SensorTimes As (
    SELECT sensorID, MAX(timestamp) "LastReading" 
    FROM sensorTable 
    GROUP BY sensorID 
) 
SELECT s.sensorID,s.timestamp,s.sensorField1,s.sensorField2 
FROM sensorTable s 
INNER JOIN SensorTimes t on s.sensorID = t.sensorID and s.timestamp = t.LastReading 
+0

這隻適用於MSSQL,對吧? –

+0

@juergend和oracle,postgresql,DB2等等。這是sql99標準的一部分。 –

13

你可以加入表本身(傳感器ID),並添加left.timestamp < right.timestamp作爲連接條件。然後你挑選行,其中right.idnull。瞧,你有每個傳感器的最新條目。

http://sqlfiddle.com/#!9/45147/37

SELECT L.* FROM sensorTable L 
LEFT JOIN sensorTable R ON 
L.sensorID = R.sensorID AND 
L.timestamp < R.timestamp 
WHERE isnull (R.sensorID) 

但請注意,這將是非常耗費資源,如果你有IDS和許多值的少量!所以,我不會推薦這種測量材料,每個傳感器每分鐘收集一個值。然而,在一個用例中,您需要跟蹤「有時」更改的「修訂」,這很容易。

+2

對於一個不尋常的解決方案+1(我想發佈相同,但):) – fancyPants

+0

謝謝,你剛剛救了我的生命:) – yossico

+0

@yossico不客氣。 – dognose

30

爲了完整起見,這裏的另一個可能的解決方案:

SELECT sensorID,timestamp,sensorField1,sensorField2 
FROM sensorTable s1 
WHERE timestamp = (SELECT MAX(timestamp) FROM sensorTable s2 WHERE s1.sensorID = s2.sensorID) 
GROUP BY sensorID; 

漂亮的自我解釋,我認爲,但here's如果你想更多的信息,以及其他的例子。它來自MySQL手冊,但上面的查詢適用於每個RDBMS(實施sql'92標準)。

+0

我的最愛迄今。對我來說,它會更好。 –

5

這可以使用SELECT DISTINCT相對優雅的方式去完成的,如下:

SELECT DISTINCT ON (sensorID) 
sensorID, timestamp, sensorField1, sensorField2 
FROM sensorTable 
ORDER BY sensorID, timestamp DESC; 

上述工作對PostgreSQL(一些更多的信息here),但我認爲還有其他的發動機。在不明顯的情況下,這是通過傳感器ID和時間戳(從最新到最舊)對錶格進行排序,然後爲每個唯一的傳感器ID返回第一行(即最新的時間戳)。

在我的使用案例中,我從〜1K個傳感器獲得了大約10M個讀數,所以試圖在基於時間戳的過濾器上加入表格本身非常耗費資源;上面需要幾秒鐘。

相關問題