Werte addieren, mit komplizierten Bedingungen

Hier kommen Posts zu anderen Datenbanken als PostgreSQL rein.
paludi06
Neuer Benutzer
Beiträge: 5
Registriert: Mo 27. Feb 2012, 08:30

Werte addieren, mit komplizierten Bedingungen

Beitrag von paludi06 » Mo 27. Feb 2012, 08:41

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

ads
Erfahrener Benutzer
Beiträge: 4148
Registriert: Mi 8. Feb 2006, 10:58
Wohnort: MD
Kontaktdaten:

Beitrag von ads » Mo 27. Feb 2012, 09:20

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?
Xandrian: Kurz gesagt: Du hast ein falsches Konzept und willst nicht auf ads hören Bild

Jetzt NEU: PostgreSQL - Datenbankpraxis für Anwender, Administratoren und Entwickler

PostgreSQL Service & Support

paludi06
Neuer Benutzer
Beiträge: 5
Registriert: Mo 27. Feb 2012, 08:30

Beitrag von paludi06 » Mo 27. Feb 2012, 09:34

ads hat geschrieben: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!

castorp
Erfahrener Benutzer
Beiträge: 1174
Registriert: Sa 27. Jun 2009, 22:24
Wohnort: Bayern

Beitrag von castorp » Mo 27. Feb 2012, 09:39

paludi06 hat geschrieben: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.
A SQL query walks into a bar and sees two tables. He walks up to them and says 'Can I join you?'

akretschmer
Erfahrener Benutzer
Beiträge: 7677
Registriert: So 29. Okt 2006, 13:35
Wohnort: Kaufbach, Sachsen, Germany, Germany
Kontaktdaten:

Beitrag von akretschmer » Mo 27. Feb 2012, 09:42

castorp hat geschrieben: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
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

paludi06
Neuer Benutzer
Beiträge: 5
Registriert: Mo 27. Feb 2012, 08:30

Beitrag von paludi06 » Mo 27. Feb 2012, 09:57

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

Code: Alles auswählen

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:

Code: Alles auswählen

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

castorp
Erfahrener Benutzer
Beiträge: 1174
Registriert: Sa 27. Jun 2009, 22:24
Wohnort: Bayern

Beitrag von castorp » Mo 27. Feb 2012, 10:39

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

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

Code: Alles auswählen

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)

Code: Alles auswählen

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
A SQL query walks into a bar and sees two tables. He walks up to them and says 'Can I join you?'

paludi06
Neuer Benutzer
Beiträge: 5
Registriert: Mo 27. Feb 2012, 08:30

Beitrag von paludi06 » Mo 27. Feb 2012, 11:16

castorp hat geschrieben:Ich versteh nicht, warum Du bei einer relationalen Datenbank Beispieldaten "zeilenweise" verwendest.

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

Code: Alles auswählen

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.


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.

castorp hat geschrieben:Ich denke das folgende Statement liefert das was Du willst (zumindest liefert es genau das Ergebnis welches Du "zeilenweise" angegeben hast)

Code: Alles auswählen

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


Ich hätte noch kurz 2 Fragen zum Code, da ich das ganze wieder von meinem Beispiel zu meinem "größeren" Problem übersetzen muss :)
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.

castorp
Erfahrener Benutzer
Beiträge: 1174
Registriert: Sa 27. Jun 2009, 22:24
Wohnort: Bayern

Beitrag von castorp » Mo 27. Feb 2012, 11:33

paludi06 hat geschrieben:Ich hätte noch kurz 2 Fragen zum Code, da ich das ganze wieder von meinem Beispiel zu meinem "größeren" Problem übersetzen muss :)
Könntest du vielleicht kurz was dazu sagen, was "first_value", "partition", "order by case" und "0 else 1" genau machen?


"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

paludi06 hat geschrieben:Ist das "t" nach der Klammer ein alias oder was hat das für eine Bedeutung?
Ja. Das ist ein Alias für die "derived table" (sub-select). Unter Oracle nicht zwingend notwendig, ist aber guter Stil.
A SQL query walks into a bar and sees two tables. He walks up to them and says 'Can I join you?'

ads
Erfahrener Benutzer
Beiträge: 4148
Registriert: Mi 8. Feb 2006, 10:58
Wohnort: MD
Kontaktdaten:

Beitrag von ads » Mo 27. Feb 2012, 14:13

Ihr vergesst, dass der Code dann auf Oracle laufen muss ;-)
Xandrian: Kurz gesagt: Du hast ein falsches Konzept und willst nicht auf ads hören Bild

Jetzt NEU: PostgreSQL - Datenbankpraxis für Anwender, Administratoren und Entwickler

PostgreSQL Service & Support

Antworten