Vermeintlich einfache Abfrage

Guten Tag,
ich bin Neuling auf dem Gebiet und verzweifle an einer, so denke ich immer noch, einfachen Abfrage.
Im Anhang habe ich die besagte Tabelle angehangen.
Ziel ist es zum Beispiel den Messwert für das Jahr 1989 zu ermitteln. Dies ist nicht das Problem, jedoch wurde der Punkt “1017” auch im Jahr 1999 gemessen. Der soll daraufhin keine Berücksichtigung finden. Das Ergebnis soll nur den Punkt “1021” anzeigen.

Hier mein Ansatz:
select m.gp_nr, m.messwert from ta_messdaten m where m.datum BETWEEN ‘1989-01-01’ AND ‘1989-12-31’!

Das Ergebnis sind nun logischerweise beide Punkte, jedoch möchte ich auch nur den haben der keine spätere Messung mehr hat. Sprich den Punkt “1021”
Habe nun schon viel probiert und erhoffe mir hier einen denkanstoß zu bekommen.

Gruß
PGForum.PNG

So ganz versteh ich noch nicht, was Du suchst, aber es könne eine Kombination von ORDER BY und LIMIT sein.

Ich suche eigentlich nur die Punktnummer samt Messwert für ein bestimmtes Jahr, sagen wir mal 1989. Die ist ja kein Problem.
Gleichzeitg möchte ich aber jene Punkte ausschließen, die einen späteren Messwert noch besitzen.
Genauer bedeutet das für die angehangte Tabelle:
Punkt: 1021 wurde das letzte mal 1989 gemessen und soll als Ergebnis erscheinen.
Punkt 1017 wurde auch im Jahr 1989 gemessen, aber weiterhin auch in 1994, 1999. Deshalb soll er keine Berücksichtigung finden, sondern nur jene die auch das letzte mal gemessen wurden im definierten Jahr.
Ich hoffe ich konnte mich verständlicher ausdrücken :slight_smile:
Danke!

Sowas in der Art:

select m.gp_nr, 
       m.messwert 
from ta_messdaten m 
where m.datum between date '1989-01-01' AND date '1989-12-31'
and not exists (select *
                from ta_messdaten m2
                where m2.datum > date '1989-12-31'
                  and m2.gp_nr = m.gp_nr);

(Ich bevorzuge die Schreibweise DATE ‘1989-01-01’ weil das ANSI SQL ist und ich nicht bei jedem DBMS umdenken muss)

Perfekt, genau das war es was ich gebraucht habe.
Schönen Dank! :smiley:

Weniger aufwändig die “Kombination von ORDER BY und LIMIT”:

SELECT gp_nr, messwert
   FROM ta_messdaten
   GROUP BY id
   HAVING extract(year FROM datum) = 1989
   ORDER BY datum DESC
   LIMIT 1;

Hallo, ich bin es nochmal. Danke für eure Antworten! Meine Ausgangslage hat sich nochmal geändert.
Ich muss zur Nullmessung (=1.Messung bzw. früheste Messung) eine Differenz berechnen.
Praktisch: 227.8710-227.9790

Den Code für die beiden Zahlen habe ich soweit hinbekommen. Nur schaffe ich es nicht beide zu integrieren das ich nur noch eine Anweisung habe.

Mein Ansatz:

select m.gp_nr,  m.messwert from ta_messdaten m 
where m.datum between date '1999-01-01' AND date '1999-12-31'
and not exists (select * from ta_messdaten m2 where m2.datum > date '1999-12-31'and m2.gp_nr = m.gp_nr);

–> liefert mir als Wert die 227.8710

SELECT m.gp_nr,m.datum,m.messwert FROM ta_messdaten m
WHERE  m.datum = (
  SELECT MIN(b.datum)
  FROM ta_messdaten b
  WHERE b.gp_nr = m.gp_nr and b.gp_nr='1017' )and m.gp_nr='1017'

–> Liefert mir als Wert: 227.9790

Jedoch möchte ich nicht beide ausführen, sondern gleich in der SQL Anweisung die Differenz berechnen.
PGForum_neu.PNG

Du suchst window-Funktionen. lag() z.B. liefert Dir innhalb eines Window bzw. Frame den Vorgänger (optional den nten Vorgänger), first_value den ersten Wert.

test=*# select * from sammer ;
 g | o | val
---+---+-----
 1 | 1 |  10
 1 | 2 |  20
 1 | 3 |  25
 2 | 1 |   1
 2 | 2 |   4
 2 | 3 |   6
 3 | 1 |   9
 3 | 2 |   8
 3 | 3 |   7
(9 rows)

test=*# select g, val, first_value(val) over (partition by g order by o), val - first_value(val) over (partition by g order by o) from sammer ;
 g | val | first_value | ?column?
---+-----+-------------+----------
 1 |  10 |          10 |        0
 1 |  20 |          10 |       10
 1 |  25 |          10 |       15
 2 |   1 |           1 |        0
 2 |   4 |           1 |        3
 2 |   6 |           1 |        5
 3 |   9 |           9 |        0
 3 |   8 |           9 |       -1
 3 |   7 |           9 |       -2
(9 rows)

g ist die Gruppe, o ein Sortiermerkmal innerhalb der Gruppe. rest: sieh Doku.

So ich habe mich ein wenig damit beschäftigt:

select m.gp_nr, m.messwert, first_value(a.messwert) over (partition by a.datum order by a.gp_nr)from ta_messdaten m, ta_messdaten a 
where m.datum between date '1989-01-01' AND date '1989-12-31' 
and not exists (select * from ta_messdaten m2 where m2.datum > date '1989-12-31' and m2.gp_nr = m.gp_nr )and m.gp_nr=a.gp_nr

Die Berechnung führt er soweit aus, mein Problem liegt jetzt darin, dass die 1. Berechnung passt, aber er den “first value” im weiteren verlauf einfach erhöht. Übersehe ich da ein Problem?

Du partitionierst nach Datum, ich denke aber, Du willst nach der Spalte, die 1017 enthaelt, partitionieren, oder ?

select m.gp_nr, m.messwert, first_value(a.messwert) over (partition by a.gp_nr order by a.gp_nr)from ta_messdaten m, ta_messdaten a 
where m.datum between date '1989-01-01' AND date '1989-12-31' 
and not exists (select * from ta_messdaten m2 where m2.datum > date '1989-12-31' and m2.gp_nr = m.gp_nr )and m.gp_nr=a.gp_nr

Die erste Zeile des Punktes 1021 passt, jedoch die erste Zeile des Punktes 1230 past nicht. Hier nimmt er beides mal den gleichen Wert, warum auch immer :confused:
Erg.PNG

over (partition by a.gp_nr order by a.gp_nr) ergibt recht wenig Sinn.

Neuer Versuch:

select m.gp_nr, m.messwert, first_value(a.messwert) over (partition by a.gp_nr order by a.datum)from ta_messdaten m, ta_messdaten a 
where m.datum between date '1989-01-01' AND date '1989-12-31'  and m.gp_nr=a.gp_nr
and not exists (select * from ta_messdaten m2 where m2.datum > date '1989-12-31' and m2.gp_nr = m.gp_nr and m2.gp_nr=a.gp_nr and m.gp_nr=a.gp_nr )and m.gp_nr=a.gp_nr

Hier stimmen die Werte, aber die Menge der Ergebnis ist zu hoch. Eine Idee wie man das unterbinden kann.

so klappt es jetzt

select Distinct m.gp_nr, m.messwert, first_value(a.messwert) over (partition by a.gp_nr order by a.datum)from ta_messdaten m, ta_messdaten a 
where m.datum between date '1989-01-01' AND date '1989-12-31'  and m.gp_nr=a.gp_nr
and not exists (select * from ta_messdaten m2 where m2.datum > date '1989-12-31' and m2.gp_nr = m.gp_nr and m2.gp_nr=a.gp_nr and m.gp_nr=a.gp_nr )and m.gp_nr=a.gp_nr

Erg2.PNG

So ich bin es nochmal. Habe ein weiteres Anliegen bezüglich meiner Aufgabe. Ich hoffe es wird nicht zu undurchsichtig.

Der unten stehende Code funktioniert eigentlich einwandfrei!

select Distinct m.gp_nr,k.rechtswert,k.hochwert, (m.messwert - first_value(a.messwert) over (partition by a.gp_nr order by a.datum)) as dif from ta_messdaten m, ta_messdaten a,ta_kopfdaten k where m.datum between date '2008-01-01' AND date '2008-12-31'  and m.gp_nr=a.gp_nr and k.gp_nr=a.gp_nr and k.gp_nr=m.gp_nr and not exists (select * from ta_messdaten m2 where m2.datum > date '2008-12-31' and m2.gp_nr = m.gp_nr and m2.gp_nr=a.gp_nr and m.gp_nr=a.gp_nr )and m.gp_nr=a.gp_nr;

Um diesen aber zu verfeinern möchte ich eine weitere Klausel einbauen die folgendes bewirken soll:

pkt 1: gemessen 1950=100cm
gemessen 2008= 101cm --> Ergebnis 1cm
pkt 2: gemessen 2008= 200cm --> Ergebnis 0cm

Ich möchte die Rechnung unter Pkt. 2 ausschließen, da nur ein Messwert vorliegt. Es kommt immer 0 raus, was in meiner Anwendung dann keine Aussagekraft hat und entfallen soll.
Hier mein Ansatz: Habe versucht eine aggregatfunktion in der having methode einzubauen. Jedoch erhalte ich hier keine Lösungsmenge, was ich mir nicht erklären kann.

select Distinct m.gp_nr,k.rechtswert,k.hochwert, (m.messwert - first_value(a.messwert) over (partition by a.gp_nr order by a.datum)) as dif from ta_messdaten m, ta_messdaten a,ta_kopfdaten k where m.datum between date '2008-01-01' AND date '2008-12-31'  and m.gp_nr=a.gp_nr and k.gp_nr=a.gp_nr and k.gp_nr=m.gp_nr and not exists (select * from ta_messdaten m2 where m2.datum > date '2008-12-31' and m2.gp_nr = m.gp_nr and m2.gp_nr=a.gp_nr and m.gp_nr=a.gp_nr )and m.gp_nr=a.gp_nr group by m.gp_nr,k.rechtswert,k.hochwert,m.messwert,a.messwert,a.gp_nr,a.datum
having COUNT (m.messwert)>1;

Falls hier noch einer durchsteigt freue ich mich auf eine Antwort. Danke!

Zähle, wie oft je Punkt gemessen wird. Ist das kleiner 2, dann ignoriere.

test=*# select * from foo;
 punkt | jahr
-------+------
     1 | 1990
     1 | 1991
     1 | 1992
     2 | 1990
     3 | 1990
     3 | 1991
(6 rows)

Time: 0,142 ms
test=*# select * from foo where punkt in (select punkt from (select punkt, count(*) from foo group by punkt) bla wherecount >=2);
 punkt | jahr
-------+------
     1 | 1990
     1 | 1991
     1 | 1992
     3 | 1990
     3 | 1991
(5 rows)

Vielen Dank für die schnelle Antwort.
Wieder genau meine Frage beantwortet :smiley:
Konnte es einwandfrei einarbeiten.

Schön - nur kann ich mir dafür auch nix kaufen :frowning:

Guten Tag allerseits,
bin gerade dabei mein SQL-Statement weiter zu verfeinern. Ich hoffe ich kann mein Problem anständig erläutern
Derzeit stellt er sich wie folgt dar:

"select Distinct m.gp_nr,k.rechtswert,k.hochwert, round((m.messwert - first_value(a.messwert) over (partition by a.gp_nr order by a.datum)),3) as dif from ta_messdaten m, ta_messdaten a,ta_kopfdaten k "
				+ "where m.datum between date '"
				+ jahr
				+ "-01-01' AND date '"
				+ jahr
				+ "-12-31' and m.gp_nr=a.gp_nr and k.gp_nr=a.gp_nr and k.gp_nr=m.gp_nr "
				+ "and not exists (select * from ta_messdaten m2 where m2.datum > date '"
				+ jahr
				+ "-12-31' and m2.gp_nr = m.gp_nr and m2.gp_nr=a.gp_nr and m.gp_nr=a.gp_nr )and m.gp_nr in (select gp_nr from ( select gp_nr,count(*) from ta_messdaten group by gp_nr) b where count >=2) and m.gp_nr=a.gp_nr order by m.gp_nr "

Diese Abfrage funktioniert auch so wie sie soll. Jetzt zu meinem Problem:

round((m.messwert - first_value(a.messwert)

Die oben zusehende Rechnung beruht auf zwei Messwerten. Jedoch gibt es eine weitere Spalte mit Messwerten, namens ‘Messwert interpoliert’. Jedoch ist immer nur eine der beiden gefüllt. Ferner möchte ich die Berechnung ändern, dass wenn m.messwert leer ist, er dafür m.messwert interpoliert nimmt.
Müsste man dies in mehrere Abfragen aufdröseln? Ich hoffe es ist verständlich andernfalls könnte ich ein Beispiel erzeugen.
Gruß Andi

Du suchst coalesce().