dbox3
Goto Top

Oracle Detailtabelle mit mehreren Zeilen - das üben wir noch mal - Biber

Hallo,
ich habe bereits mehrere Beiträge gegoogelt, jedoch passt keine Lösung so richtig zu meinem Problem. Ich habe in meiner Oracle-DB u.a. drei Tabellen, die ich gerne analysieren würde.
Tab 1 Leistungsziffern
KEYID LEISTUNG GUELTIG_VON GUELTIG_BIS
205 2300 01.01.13 31.12.13
206 2300 01.07.13 30.09.13
207 2300 01.10.13 31.12.13
208 2301 01.01.13 31.03.13
209 2301 01.04.13 31.12.13
210 2301 01.10.13 31.12.13

Tab 2 Preise
KEYID BETRAG
205 10,05
206 11,10
207 11,60
208 23,20
209 23,70
210 24,10

Tab 3 Leistungen
DATUM LEISTUNG

02.01.13 2300

Mein Problem ist, dass die Gültigkeitszeiträume der Preise für einzelne Leistungen sich ändern und z.T. Überlappen (d.h. GUELTIG_BIS öfters übereinstimmen) und wenn ich nun eine Abfrage wie folgt erstelle:

SELECT A.LEISTUNG, SUM(B.Betrag)
FROM Leistungsziffern A
INNER JOIN Preise B
ON A.KEYID = B.KEYID
INNER JOIN Leistungen C
ON A.LEISTUNG = C.LEISTUNG
WHERE C.DATUM >= '01.01.13'

bekomme ich viel höhere Summen, da mehrere Zeilen aus der 1. Tabelle zu jedem Zeitraum geliefert werden und somit in die Summe einfließen.
Ich bin so weit, dass ich mit einer Unterabfrage einen gültigen Preis für ein konkretes Datum herausfitern kann. Wie ich jedoch für einen größeren Zeitraum (z.B. TRUNC(DATUM,‘Q‘)) abfragen kann, bekomme ich nicht hin. Diese Variante:

SELECT SUM(B.Betrag), TRUNC(C.DATUM,'Q')
FROM Leistungsziffern A
INNER JOIN Preise B
ON A.KEYID = B.KEYID
INNER JOIN Leistungen C
ON A.LEISTUNG = C.LEISTUNG
INNER JOIN
(SELECT D.LEISTUNG, MAX(D.GUELTIG_VON)
FROM Leistungsziffern D INNER JOIN Leistungen F ON D.LEISTUNG = F.LEISTUNG
WHERE D.GUELTIG_VON < F.DATUM AND F.DATUM >= '01.01.2013‘
GROUP BY D.LEISTUNG) E
ON A.LEISTUNG = E.LEISTUNG
WHERE C.DATUM >= '01.01.13'
GROUP BY TRUNC(C.DATUM,'Q')

löst das Dilemma nicht. Wer kann helfen.
Danke

Content-Key: 293387

Url: https://administrator.de/contentid/293387

Printed on: April 25, 2024 at 12:04 o'clock

Member: dbox3
dbox3 Jan 17, 2016 at 16:04:48 (UTC)
Goto Top
Die Frage ist offensichtlich zu kompliziert oder zu blöd, um auf eine Antwort zu hoffen. Wäre jemand vielleicht behilflich, einen Link zur möglichen Lösungssuche zu posten?
Danke
Member: BirdyB
BirdyB Jan 17, 2016 at 16:19:22 (UTC)
Goto Top
Hallo dbox3,

ich weiß ja nicht, was du dir hier so vorstellst, aber dies ist ein Internetforum, in dem Leute in ihrer Freizeit(!) anderen helfen, ihre IT-Problemchen zu lösen...
Dein Beitrag ist jetzt genau 7 Stunden hier im Forum. Was stellst du dir vor? Hilfe für jedes Problem in < 4h? Kannst du haben... Nicht hier... Und definitiv nicht umsonst...
Und wenn du Links brauchst, versuch es mit google...

Beste Grüße!


Berthold
Member: dbox3
dbox3 Jan 18, 2016 at 06:57:41 (UTC)
Goto Top
Das war ja ein toller Beitrag! Freizeit für eine solche Belerung hast du offenbar genug. Und wenn ich eine gebraucht hätte, würde ich auch danach fragen. Gefragt habe ich jedoch nach einem Lösungsvorschlag. Den hast du offensichtlich nicht. Es gab Zeiten hier, wo man innerhalb kürzester Zeit zumindest eine Antwort bekommen hat (auch umsonst), und darauf habe ich gehofft. Geld für Hilfe habe ich hier überigens auch schon gezahlt. Das soll aber kein Vorwurf sein. Das Problem würde ich trotzdem gerne gelöst haben.
Member: BirdyB
BirdyB Jan 18, 2016 at 07:13:35 (UTC)
Goto Top
Dein unverschämtes Verhalten steigert die Motivation der Kollegen bestimmt ungemein, über eine Lösung für dein Problem nachzudenken...
Ich jedenfalls hab keine Lust mehr... Ich bin raus...
Member: TheJoker2305
Solution TheJoker2305 Jan 18, 2016 updated at 22:03:57 (UTC)
Goto Top
Hallo zusammen,

auch wenn einem eine Frage unter den Nägeln brenn,t ist Geduld oft trotzdem angebracht.
Außerdem war Sonntag - und ich glaube da ist der Andrang in diesem Forum etwas verhaltener als in der Woche ... oder face-smile

Zur Lösung des Problems:
Ich gehe davon aus, dass der Zeitraum mit der höchsten keyid der gültige für den entsprechenden Leistungstag ist.

Folgendes Statement sollte funktioniert zumindest auf meinem TSQL-Server, ggfs. muss noch die Syntax für Oracle abgewandelt werden:

SELECT L.Datum, L.Leistung, P.Betrag FROM Leistungen L
INNER JOIN (SELECT L2.Datum AS Datum, L2.Leistung AS Leistung, MAX(LKZ.KeyID) AS KeyID FROM Leistungen L2
            INNER JOIN Leistungskennziffern LKZ on L2.Datum between LKZ.Gueltig_von and LKZ.Gueltig_bis and L2.Leistung = LKZ.Leistung
GROUP BY L2.Datum, L2.Leistung) D on L.Datum = D.Datum and L.Leistung = D.Leistung
INNER JOIN Preise P on D.KeyId = P.KeyId
ORDER BY L.Datum, L.Leistung

So und nun habt euch wieder lieb face-smile

Beste Grüße
thejoker2305
Member: Biber
Biber Jan 18, 2016 updated at 10:51:05 (UTC)
Goto Top
Moin TheJoker2305,

wenn der ungeduldige TO in Zeile 3 den Tabellennamen "Leistungskennziffern" in "Leistungsziffern" ändert, dann funktioniert dein Ansatz auch unter Oracle. face-wink

Jedenfalls mit den obigen Beispieldaten.


Grüße
Biber
Member: TheJoker2305
Solution TheJoker2305 Jan 18, 2016 updated at 22:04:16 (UTC)
Goto Top
Moin Biber,

jupp, da hast du recht.
Der Begriff "Leistungsziffern" war mir einfach zu fremd ... obwohl ja "Kennziffern" narütlich nicht auf die Tabelle zutreffen würde face-smile eher "Leistung_Gueltigkeit"

Geht bestimmt auch einfacher, aber erstmal soll es ja funktionieren face-smile
Vieleicht meldet sich der TO ja noch, ob es so für ihn passt. face-smile

Beste Grüße
thejoker2305
Member: Biber
Biber Jan 18, 2016 updated at 22:59:27 (UTC)
Goto Top
Moin TheJoker2305,

Zitat von @TheJoker2305:

Geht bestimmt auch einfacher, aber erstmal soll es ja funktionieren face-smile
Vieleicht meldet sich der TO ja noch, ob es so für ihn passt. face-smile
Na ja, wenn ich mich hiermit befassen wollte, dann würde ich vermutlich ein paar JOINs weniger verwenden...
Select Trunc(L.Datum,'Q') as Quartal, L.Leistung, sum(p.Betrag) from Leistungen L   
join Leistungsziffern LZ on L.leistung = lz.leistung and l.datum between lz.gueltig_von and lz.gueltig_bis
join Preise P on p.keyid=lz.keyid
where not exists (select 1 from leistungsziffern lz2 where l.datum between lz2.gueltig_von and lz2.gueltig_bis and lz2.gueltig_von >lz.gueltig_von) 
group by Trunc(L.Datum, 'Q'), L.leistung  
order by  1, 2;

Das sollte (in der Theorie) auch alle Beträge nach Quartal und Leistung ausgeben, wenn denn zu jedem Leistungsdatum EIN passender Gültigkeits-Zeitraum gefunden wird,

Aber warum sollte ich einem unfreundlichen TO zuarbeiten?

Ach was solls...
@dbox3
a) Bitte überdenke deine Anspruchshaltung. Ich kenne Moderatoren, die sind manchmal etwas reizbar, wenn sie am Montachmorgen vor dem ersten Liter Kaffee einen Beitrag dieses Kalibers vorfinden.
b)
und wenn ich nun eine Abfrage wie folgt erstelle:

SELECT A.LEISTUNG, SUM(B.Betrag)
FROM Leistungsziffern A
INNER JOIN Preise B
ON A.KEYID = B.KEYID
INNER JOIN Leistungen C
ON A.LEISTUNG = C.LEISTUNG
WHERE C.DATUM >= '01.01.13'

bekomme ich viel höhere Summen,
Nein, dann bekommst du einen
ORA-00937: keine Gruppenfunktion für Einzelgruppe [SQL State=42000, DB Errorcode=937]
Und das zu Recht.

WHERE D.GUELTIG_VON < F.DATUM AND F.DATUM >= '01.01.2013‘
...
WHERE C.DATUM >= '01.01.13'
Was sollen denn diese redundanten Bedingungen in EINEM Statement?
Erstens ist DATUM doch hoffentlich ein Datumsfeld. (sonst würde ja auch dein TRUNC(DATUM, 'Q') in die Grütze gehen)
Also solltest du es nicht mit einem String vergleichen, sondern mit TO_DATE('01.01.2013', 'dd.mm.yyyy')

Zweitens reicht es einmalig als WHERE-Bedingung für das Gesamtresultat statt redundant in jedem verwendeten JOIN.

Und grundsätzlich: das eigentliche Problem deiner Tabellenstruktur sind die überlappenden Gültigkeitsbereiche.
Warum machst du nicht einfach ein Update der LEISTUNGSZIFFERN.GUELTIG_BIS-Felder, damit sichergestellt ist, dass zu jedem LEISTUNGEN.DATUM genau ein Satz mit passendem Gültigkeitsbereich gefunden wird?

Datenbank-Tabellen und Beliebigkeit und Mehrdeutigkeit ... das geht ja nun gar nicht.
Auch nicht an Tagen, die nicht mit "Mon" beginnen.


Grüße
Biber

P.S. Upps, grade gelesen, dass dieser Beitrag schon von 3 Mitgliedern als "Unverschämt" gemeldet wurde...
Mach ich nach dem Mittach weg.
Member: Biber
Biber Jan 18, 2016 updated at 13:03:41 (UTC)
Goto Top
Moin nochmal,

da dieser Beitrag mehrfach als "unverschämt" gemeldet wurde und deshalb nicht zu erwarten ist, dass auch nur einer unserer geschätzten SQL-Gurus in diesem Forum freudigst Perlen vor diesen TO wirft, mache ich das, was ich montachs am Besten kann.

back-to-top### Papierkorb ###


Biber
@dbox3
Die Frage ist offensichtlich zu kompliziert oder zu blöd, um auf eine Antwort zu hoffen.
Nein, du hättest mit Sicherheit Lösungsvorschläge erhalten.
Das hast du dir aber kurz vor dem Ziel selbst verbaut mit deinen ersten beiden Kommentaren.
Member: dbox3
dbox3 Jan 18, 2016 at 20:37:30 (UTC)
Goto Top
Ich bin fälschlicherweise davon ausgegangen, dass Sonntags mehr Leute mehr Zeit haben und meine Frage einfach übersehen wurde oder falsch formuliert wurde und die Lösung zu einfach, um sich damit zu befassen. So erklärt sich meine Ungeduld und mein erstes Kommentar, der jedoch nicht böse gemeint war. Dafür mein SORRY. Beiträge nach dem Motto "guck doch mal bei Google nach, falls du Hilfe brauchst" kann man sich sicher sparen, vor allem dann, wenn man nichts zur Sache zu sagen hat. Für die Lösungsvorschläge trotzdem vielen Dank. Ich bin heute sehr spät nach Hause gekommen und noch nicht geschafft, diese auszuprobieren.
Gruß
dbox3
Member: BirdyB
BirdyB Jan 18, 2016 at 20:44:40 (UTC)
Goto Top
Abschließend von meiner Seite: Der Verweis auf google ist lediglich die Reaktion auf deinen recht unverschämten Post...
Mir vergeht bei dieser Erwartungshaltung lediglich die Lust konkret über Lösungen nachzudenken und diese zu formulieren.
Sonst hätte die Antwort auch deutlich anders ausgesehen.
Es freut mich, dass du zu der Erkenntnis gelangt bist, dass dein Posting recht unglücklich gewählt war...
Also: Peace face-wink
Member: Biber
Biber Jan 18, 2016 updated at 22:51:51 (UTC)
Goto Top
Moin dbox3,

danke für die Rückmeldung und für dein Sorry - ist von meiner Seite aus auch damit erledigt.
Und auch die meisten anderen hier sind durchaus nicht nachtragend.

Also lass uns alle wieder lieb sein, wie TheJoker2305 es ausdrückte und dieses eigentliche Problemchen gemeinsam lösen.

Meinetwegen auch erst morgen.
Ich meine, ich habe ja alle Zeit dieser Welt dafür... face-wink

Grüße
Biber
Member: dbox3
dbox3 Jan 18, 2016 at 22:08:23 (UTC)
Goto Top
Freut mich auch. Die Lösung hat aber auf Anhieb gut funktioniert. Nochmal vielen Dank face-smile
Member: Biber
Solution Biber Jan 19, 2016, updated at Jan 21, 2016 at 21:59:14 (UTC)
Goto Top
Moin dbox3,

auch wenn der Beitrag schon als gelöst gekennzeichnet ist...

ich möchte darauf hinweisen, dass sowohl TheJoker2305s wie auch mein Statement beides Schönwetterlösungen sind, die von (unrealistisch) optimistischen Annahmen ausgehen.

TheJoker2305 schreibt:
Zitat von @TheJoker2305:

Zur Lösung des Problems:
Ich gehe davon aus, dass der Zeitraum mit der höchsten keyid der gültige für den entsprechenden Leistungstag ist.

Tja, kann man annehmen... aber ob die Realität sich daran hält...?

Und bei mir klappt es mit dem Ausfiltern der überschneidenden Zeiträume auch nur wirklich, wenn es mehrere passende "Zeiträume" gibt mit gleichen GUELTIG_BIS-Datum und unterschiedlichen GUELTIG_VON-Datum.
Sprich, wenn folgende Konstellation gegeben wäre
KEYID LEISTUNG GUELTIG_VON GUELTIG_BIS
666 2300 01.01.2013 01.04.2013
667 2300 01.01.2013 01.07.2013
...

-> dann bekommst du auch ein falsches Ergebnis bzw. doppelte Sätze.
Wobei "falsch" hier natürlich relativ ist... die Daten sind halt nicht konsistent.
Deshalb noch mal der Hinweis: mache durch ein Update der GUELTIG_BIS-Felder die Daten überschneidungsfrei.

Grüße
Biber
Member: dbox3
dbox3 Jan 21, 2016 at 22:00:02 (UTC)
Goto Top
Die GUELTIG_VON Felder sind immer eindeutig, daher bekomme ich ein wohl glaubhaftes Ergebnis und das reicht mir im Moment. Ein Update der Tabelle wäre sicher optimal. Die Datenbank wurde aber nicht von mir erstellt, und ich möchte an der Struktur grundsätzlich nichts ändern, damit es künftig keine Probleme nach einem Software-Update gibt. Trotzdem Danke für den Tipp.