Werte addieren, mit komplizierten Bedingungen

Hallo zusammen,

ich habe ein Problem und ich weiß nicht so recht, wie ich es in SQL (Oracle) richtig löse. Wäre echt super, wenn ihr mir helfen könnt!
Es geht um folgendes:
Ich habe eine Tabelle mit Spalten “Zustand”, “Zins”, “Nummer”, “Wert”, “Art”.
Ausprägungen von “Zustand” sind z.B.: A; B; C; D; E
von “Zins”: 0.03; 0.035; 0.04; 0.02
von “Nummer:” 1; 2; 3
von “Wert”: irgendwelche Zahlen
von “Art”: HV; GB; ZT

Als Ausgabe will ich nun folgendes:
Es soll über alle “Werte” addiert werden, wobei über “Zustand” und “Zins” gruppiert werden soll.
Dabei soll für jede “Nummer” alle “Arten” die nicht “HV” sind, sowohl den “Zustand”, als auch den “Zins” des Eintrages bekommen, welches “HV” hat.
(Also diese Sachen sollen dazu addiert werden, die ursprüngliche Tabelle soll nicht verändert werden)
Beispiel: (Zeilenweise, statt spaltenweise notiert)
“Zustand” A; B; C; D; E; A
“Zins” 0.03; 0.035; 0.04; 0.04; 0.02; 0.03
“Nummer” 1; 1; 1; 2; 2; 3
“Wert” 10; 2; 3; 16; 1; 7
“Art” HV GB ZT HV GB HV
(es gehört immer der 1. Wert zum 1., der 2. zum 2. etc, also A; 0,03; 1; 10; HV gehören z.B. zusammen)
Als Ergebnis will ich nun haben:
“Zustand” A D
“Zins” 0,03 0,04
“Wert” 22 17
Ich wäre euch sehr dankbar, wenn ihr mir helfen könnt. Falls ich mir irgendwo unklar ausgedrückt haben soll, fragt bitte nach, dann versuch ich mich deutlicher auszurücken.

Viele Grüße
paludi06

Zuerst einmal geht es in diesem Forum nicht um Oracle, sondern um PostgreSQL.
Und zum zweiten sieht mir das sehr stark nach einer Aufgabe aus dem Studium aus … oder?

Das tut mir leid, vielen Dank fürs verschieben.

Es handelt sich um keine Aufgabe aus dem Studium, sondern ich muss diese Daten beruflich aufbereiten.

Da ich bisher nur mit absoluten Standard-Abfragen zu tun hatte, bin ich hiermit etwas überfordert. Deshalb wäre ich für jeden Tipp dankbar!

Kannst Du die Beispiele mal etwas formatieren bitte? (Siehe hier: BB-Code Liste - PG-Forum.de)
Oder als INSERT Statement posten? (Siehe z.B. hier: The Tom Kyte Blog: How to ask questions)

So ist es wirklich sehr schwer zu lesen und zu erkennen was Du eigentlich haben willst.

Ich interpretiere es erst mal so, daß er ein select * where art = ‘HV’ sowie ein UNION ALL where art != ‘HV’ haben will, wobei dann nach Regeln, die ich noch nicht ganz durchschaue, einige Felder geändert werden müßten, um das Ganze dann zu aggregieren.

Aber die Beschreibung ist wirklich nicht allzu gut bzw. verständlich…


Andreas

Danke für eure Hilfe. Hier mal die formatierte Tabelle:

Beispiel: (Zeilenweise, statt spaltenweise notiert)
"Zustand"   A;      B;       C;       D;       E;       A 
"Zins"        0.03;  0.035;  0.04;   0.04;  0.02;   0.03
"Nummer"   1;       1;       1;       2;       2;       3
"Wert"       10;      2;       3;      16;      1;       7
"Art"         HV      GB       ZT      HV      GB      HV

Als Ergebnis will ich nun haben:
"Zustand"   A         D
"Zins"        0.03     0.04
"Wert"       22       17

Ich versuchs mal nochmal genauer zu erklären:
Zu jeder “Nummer” gibt es genau ein “HV”, und zusätzlich kann es “GB” und “ZT” geben. Diese “GB” und “ZT” Einträge können andere “Zinsen” und “Zustände” haben als das zugehörige “HV”, deshalb müssen diese umgeschlüsselt werden, zu denen des “HV”. In der Ausgabe, soll nun über alle “Werte” addiert werden, wobei über “Zustand” und “Zins” gruppiert werden soll (nicht über die “Nummer”). Dabei sollen natürlich die ursprünglichen “GB” und “ZT” Einträge nicht geändert werden, sondern nur für dieses select zum addieren.

Ich hoffe es ist etwas klarer geworden.

Als einen Miniansatz hab ich folgendes:

select a1.zustand, a1.zins, sum(a2.wert) from tabelle a1, tabelle a2
where a1.nummer = a2.nummer and a1.art ='HV'
group by a1.zustand, a1.zins

wobei hier natürlich die ganze Sache mit dem Umschlüsseln fehlt

Ich versteh nicht, warum Du bei einer relationalen Datenbank Beispieldaten “zeilenweise” verwendest.

Ich gehe mal davon aus, dass Deine Tabelle so aussieht:

Zustand     Zins     Nummer      Wert    Art
      A     0.03          1        10     HV
      B    0.035          1         2     GB
      C     0.04          1         3     ZT
      D     0.04          2        16     HV
      E     0.02          2         1     GB
      A     0.03          3         7     HV

Wenn Du jetzt noch ein CREATE TABLE und die entsprechenden INSERTs geposted hättest wäre das für uns wesentlich einfacher. So müssen wir mühsam die Testdaten selber in Inserts verwandeln und uns die Tabellendefinition irgendwie ausdenken (Schliesslich sollte man die Lösung ja auch mal ausprobieren bevor man sie postet.). Beim nächsten Mal machst Du es sicher besser.

Ich denke das folgende Statement liefert das was Du willst (zumindest liefert es genau das Ergebnis welches Du “zeilenweise” angegeben hast)

select hv_zustand,
       hv_zins,
       sum(wert) as summe
from (
  select zustand, 
         zins,
         nummer, 
         wert, 
         art,
         first_value(zins) over (partition by nummer order by case when art = 'HV' then 0 else 1 end) as hv_zins,
         first_value(zustand) over (partition by nummer order by case when art = 'HV' then 0 else 1 end) as hv_zustand
  from tabelle
) t
group by hv_zins, hv_zustand

Tut mir echt Leid, hab wie gesagt bisher kaum Erfahrungen mit Datenbanken und wie man sowas geschickt ins Forum postet.
Vielen Dank, dass du es trotzdem gelöst hast mein Problem! Wollte dir keinen unnötigen Aufwand machen.

Ich hätte noch kurz 2 Fragen zum Code, da ich das ganze wieder von meinem Beispiel zu meinem “größeren” Problem übersetzen muss :slight_smile:
Könntest du vielleicht kurz was dazu sagen, was “first_value”, “partition”, “order by case” und “0 else 1” genau machen? Ist das “t” nach der Klammer ein alias oder was hat das für eine Bedeutung?

Nochmals vielen Dank, ich werde nun mal mein Glück versuchen, ob ich es hinbekomme.

“partition by” ist im Endeffekt ein group by nur “on the fly” - man muss dabei nicht das gesamte Resultat gruppieren.

Durch das order by case … end wird innerhalb der Gruppe der Wert für HV an die erste Stelle sortiert, first_value() liefert einfach den ersten Wert der Gruppe zurück. Lass mal nur das “innere” Select alleine laufen dann siehst Du was passiert.

Ein gutes Tutorial bzgl. Windowing functions (so heissen die) kannst Du im PostgreSQL Handbuch finden: PostgreSQL: Documentation: Manuals: Window Functions

Oracle nennt das “Analytic Functions”. Der entsprechende Abschnit im Handbuch ist hier: Analytic Functions
bzw. eine etwas längere Einführung ist hier: SQL for Analysis and Reporting

Ja. Das ist ein Alias für die “derived table” (sub-select). Unter Oracle nicht zwingend notwendig, ist aber guter Stil.

Ihr vergesst, dass der Code dann auf Oracle laufen muss :wink:

Mein Beispiel läuft auf Oracle

Vielen Dank für die Erläuterungen, hat mir wirklich sehr geholfen.

Falls ich mal wieder ein Problem hab, weiß ich wohin ich mich wenden kann :wink: