2013-06-26 3 views
35

Ich habe eine Tabelle mit Sensordaten. Jede Zeile hat eine Sensor-ID, einen Zeitstempel und andere Felder. Ich möchte eine einzelne Zeile mit dem spätesten Zeitstempel für jeden Sensor auswählen, einschließlich einiger der anderen Felder.Wie kann ich Zeilen mit dem letzten Zeitstempel für jeden Schlüsselwert auswählen?

Ich dachte, dass die Lösung Gruppe von Sensor-ID sein würde und dann, um von max (Zeitstempel) wie folgt:

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

Das bin ich einen Fehler gibt zu sagen, dass „sensorField1 in der Gruppe durch Klausel erscheinen müssen oder in einem Aggregat verwendet werden. "

Was ist der richtige Weg, um dieses Problem anzugehen?

+0

Welche DB-Engine verwenden Sie? –

+0

Während die Antworten unter Verwendung von JOINs auf dem Max (Zeitstempel) -Wert funktionieren sollten, würde ich empfehlen, einer SensorReadingId beizutreten, wenn Sie eine auf der SensorTabelle haben. –

Antwort

12

Sie können nur Spalten auswählen, die sich in der Gruppe befinden oder in einer Aggregatfunktion verwendet werden. Sie können eine Verknüpfung verwenden, um diese

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

... oder 'auswählen * von sensorTable, wo (sensorID, timestamp) in (SensorID auswählen, max (Zeitstempel) von sensorTable group by sensorID)'. – Arjan

+0

Ich glaube, "LINKE VERBINDUNG" wird auch angewendet, nicht nur "INNER JOIN"; und ein Teil "und s1.timestamp = s2.mts" ist nicht erforderlich IMHO. Und dennoch empfehle ich Index auf zwei Feldern zu erstellen: SensorID + Timestamp - Abfragegeschwindigkeit steigt groß! – 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

Dies funktioniert nur mit MSSQL, oder? –

+0

@juergend Und Oracle, Postgresql, DB2 und einige andere. Dies ist Teil des sql99-Standards. –

13

Arbeit erhalten Sie die Tabelle mit sich selbst (auf Sensor-ID) beitreten können, und fügen Sie left.timestamp < right.timestamp als Join-Bedingung. Dann wählen Sie die Zeilen, wobei right.idnull ist. Voila, du hast den neuesten Eintrag pro Sensor.

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) 

Bitte beachten Sie jedoch, dass dies sehr ressourcenintensiv sein, wenn Sie eine kleine Menge von IDs und viele Werte haben! Also, ich würde dies nicht für eine Art von Messmaterial empfehlen, bei dem jeder Sensor jede Minute einen Wert erfasst. In einem Use-Case, in dem Sie "Revisionen" von etwas verfolgen müssen, das sich nur "manchmal" ändert, ist es einfach.

+2

+1 für eine ungewöhnliche Lösung (Ich wollte das gleiche, obwohl) :) – fancyPants

+0

Danke, Sie haben gerade mein Leben gerettet :) – yossico

+0

@ yossico du bist willkommen. – dognose

30

Aus Gründen der Vollständigkeit, hier ist eine andere mögliche Lösung:

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

Ziemlich selbsterklärend denke ich, aber here's weitere Informationen, wenn Sie, wie auch andere Beispiele wollen. Es stammt aus dem MySQL-Handbuch, aber die obige Abfrage funktioniert mit jedem RDBMS (implementiert den sql'92-Standard).

+0

Mein Favorit bisher. Zu mir liest es einfach besser. –

5

DE Das kann mit SELECT DISTINCT in einer relativ elegante Art und Weise erfolgen, wie folgt: für PostgreSQL (einige weitere Informationen here)

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

Die oben genannten Arbeiten, aber ich denke auch andere Motoren. Falls dies nicht offensichtlich ist, wird die Tabelle nach Sensor-ID und Zeitstempel (neu nach alt) sortiert und dann die erste Zeile (d. H. Der späteste Zeitstempel) für jede eindeutige Sensor-ID zurückgegeben.

In meinem Anwendungsfall habe ich ~ 10M Lesungen von ~ 1K Sensoren, also ist der Versuch, die Tabelle mit sich selbst auf einem Timestamp-basierten Filter zu verbinden, sehr ressourcenintensiv; Das oben genannte dauert ein paar Sekunden.

Verwandte Themen