Letzten Wert bei Mehrfachmessungen ermitteln

kwakz

Aktiver Benutzer
Beiträge
29
Hallo zusammen,

ich habe eine Datenbank, in der Messwerte von Ventilen stehen. Jedes Ventil ist durch seine Seriennnummer gekennzeichnet. Jetzt kann es vorkommen, dass ein Ventil mehrfach gemessen wurde ... beispielsweise, wenn es im ersten Durchgang als NIO bewertet wurde. Die Messungen sind durch eine Mess-ID gekennzeichnet.

Nun interessiert mich bei diesen Mehrfachmessungen immer nur der letzte Messwert, weil das Ventil mit diesem die Anlage verlassen hat. Die Frage wäre: Wie kann ich die Abfrage so gestalten, dass bei jedem Ventil immer der Messwert mit der größten Mess-ID verwendet wird?

Mfg Daniel
 
Werbung:
Hallo zusammen,

ich habe eine Datenbank, in der Messwerte von Ventilen stehen. Jedes Ventil ist durch seine Seriennnummer gekennzeichnet. Jetzt kann es vorkommen, dass ein Ventil mehrfach gemessen wurde ... beispielsweise, wenn es im ersten Durchgang als NIO bewertet wurde. Die Messungen sind durch eine Mess-ID gekennzeichnet.

Nun interessiert mich bei diesen Mehrfachmessungen immer nur der letzte Messwert, weil das Ventil mit diesem die Anlage verlassen hat. Die Frage wäre: Wie kann ich die Abfrage so gestalten, dass bei jedem Ventil immer der Messwert mit der größten Mess-ID verwendet wird?

Mfg Daniel

Abfrage auf ID des Ventiles und max(xxx) mit xxx hier z.B. der Zeitpunkt der Messung oder der ID-der Messung, wenn diese immer steigt.

Damit JOINst dann Deine Meßtabelle, um die konkreten Meßwerte zu erhalten. Du siehst jetzt den Weg?
 
Abfrage auf ID des Ventiles und max(xxx) mit xxx hier z.B. der Zeitpunkt der Messung oder der ID-der Messung, wenn diese immer steigt.

Damit JOINst dann Deine Meßtabelle, um die konkreten Meßwerte zu erhalten. Du siehst jetzt den Weg?

Um es mal zu zeigen:

Code:
test=*# select * from ventile;
 sn | mess_id | wert
----+---------+------
  1 |  1 |
  1 |  2 |  27
  1 |  3 |  38
  2 |  4 |  12
  2 |  5 |
  2 |  6 |  31
  3 |  7 |  8
  4 |  8 |  12
(8 rows)

test=*# select ventile.sn, ventile.wert from ventile inner join (select sn, max(mess_id) from ventile group by sn) foo on ((ventile.sn, ventile.mess_id)=(foo.sn,foo.max)) order by sn;
 sn | wert
----+------
  1 |  38
  2 |  31
  3 |  8
  4 |  12
(4 rows)
 
Es gibt eigentlich viele Wege. Aber alle Varianten haben gemeinsam das man nach der MessID vernünftig sortieren können muss. Wenn deine MessID nicht numerisch ist und aufsteigend vergeben wird solltest du auf ein Messdatum oder ähnliches zurück greifen.

Hier mal noch ein alternativer Weg (Datum kann man ggf. dann mit MessID tauschen wenn numerisch und aufsteigend):
Code:
SELECT    t.seriennr,
        t.datum
FROM    (

SELECT    ROW_NUMBER() OVER (PARTITION BY seriennr ORDER BY datum DESC) AS zeilennr,
        seriennr,
        datum
FROM    tabelle

) t
WHERE    t.zeilennr = 1
 
Es gibt eigentlich viele Wege.

Stimmt.

Aus dem Bauch heraus halte ich Deine Variante aber schlechter als meine, weil da immer ein Full-Table-Scan nötig wäre, um row_number() zu berechnen. Bei meinem könnte ein Index helfen und somit ein deutlich schnellerer Indexscan greifen. Ungetestet jetzt alles.
 
Da kennst du dich dann besser aus, ich hab bei meinen kleinen DBs selten Performance fragen. Allerdings müsste ein Index auf seriennr,datum doch hier auch meine Abfrage beschleunigen oder sehe ich das falsch?
 
Da kennst du dich dann besser aus, ich hab bei meinen kleinen DBs selten Performance fragen. Allerdings müsste ein Index auf seriennr,datum doch hier auch meine Abfrage beschleunigen oder sehe ich das falsch?

In Deinem inneren Select gehst Du komplett durch die Tabelle und berechnest je Row die row_number. Auf dem Resultat dann machst Du das äußere Select. Aber erst einmal machst Du halt ein Full-Table-Scan. Ob der Index der originalen Tabelle dann noch greift ist die nächste Frage ;-)
 
In Deinem inneren Select gehst Du komplett durch die Tabelle und berechnest je Row die row_number. Auf dem Resultat dann machst Du das äußere Select. Aber erst einmal machst Du halt ein Full-Table-Scan. Ob der Index der originalen Tabelle dann noch greift ist die nächste Frage ;-)

Antwort:

Code:
test=*# set enable_seqscan to off;
SET
test=*# create index idx2 on ventile (sn, wert);
CREATE INDEX
test=*# explain select ventile.sn, ventile.wert from ventile inner join (select sn, max(mess_id) from ventile group by sn) foo on ((ventile.sn, ventile.mess_id)=(foo.sn,foo.max)) order by sn;
  QUERY PLAN
-------------------------------------------------------------------------------------------
 Merge Join  (cost=0.27..24.84 rows=1 width=8)
  Merge Cond: (ventile_1.sn = ventile.sn)
  Join Filter: (ventile.mess_id = (max(ventile_1.mess_id)))
  ->  GroupAggregate  (cost=0.13..12.37 rows=8 width=8)
  ->  Index Scan using idx2 on ventile ventile_1  (cost=0.13..12.25 rows=8 width=8)
  ->  Index Scan using idx2 on ventile  (cost=0.13..12.25 rows=8 width=12)
(6 rows)



-- deine version
test=*# explain select t.* from (select row_number() over (partition by sn order by mess_id desc) as zn, * from ventile) t where t.zn=1;
  QUERY PLAN
----------------------------------------------------------------------------------------------
 Subquery Scan on t  (cost=10000000001.20..10000000001.46 rows=1 width=20)
  Filter: (t.zn = 1)
  ->  WindowAgg  (cost=10000000001.20..10000000001.36 rows=8 width=12)
  ->  Sort  (cost=10000000001.20..10000000001.22 rows=8 width=12)
  Sort Key: ventile.sn, ventile.mess_id
  ->  Seq Scan on ventile  (cost=10000000000.00..10000000001.08 rows=8 width=12)
(6 rows)
 
Hallo zusammen,

vielen Dank für die Antworten. Ich hab jetzt im Prinzip die erste Lösung ein bisschen adaptiert. Ich erzeuge mir eine temporäre Tabelle und verknüpfe die dann mit einem Inner Join.

Vielen Dank!

Mfg Daniel
 
Hm ... ich erzeuge eine temporäre Tabelle mit einer with-Anweisung ... sollte ich hier lieber einen View benutzen?
Mit WITH erzeugst du im Grunde eine benannte Menge. Temporäre Tabellen werden hingegen physisch gespeichert. WITH ist schon ok und wäre mit einer temporären VIEW zu vergleichen.
 
Werbung:
Ich meinte das du keine zusätztliche Tabelle anlegen sollst in die du deine Daten kopierst um sie dann zu joinen. WITH ist voll i.O.
 
Zurück
Oben