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
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
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 293387
Url: https://administrator.de/forum/oracle-detailtabelle-mit-mehreren-zeilen-das-ueben-wir-noch-mal-biber-293387.html
Ausgedruckt am: 15.04.2025 um 14:04 Uhr
15 Kommentare
Neuester Kommentar
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
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
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
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:
So und nun habt euch wieder lieb
Beste Grüße
thejoker2305
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
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
Beste Grüße
thejoker2305
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
eher "Leistung_Gueltigkeit"
Geht bestimmt auch einfacher, aber erstmal soll es ja funktionieren
Vieleicht meldet sich der TO ja noch, ob es so für ihn passt.
Beste Grüße
thejoker2305
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
Geht bestimmt auch einfacher, aber erstmal soll es ja funktionieren
Vieleicht meldet sich der TO ja noch, ob es so für ihn passt.
Beste Grüße
thejoker2305
Moin TheJoker2305,
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)
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.
Zitat von @TheJoker2305:
Geht bestimmt auch einfacher, aber erstmal soll es ja funktionieren
Vieleicht meldet sich der TO ja noch, ob es so für ihn passt.
Na ja, wenn ich mich hiermit befassen wollte, dann würde ich vermutlich ein paar JOINs weniger verwenden...Geht bestimmt auch einfacher, aber erstmal soll es ja funktionieren
Vieleicht meldet sich der TO ja noch, ob es so für ihn passt.
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 einenSELECT 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,
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?...
WHERE C.DATUM >= '01.01.13'
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.
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.
Biber
@dbox3
Das hast du dir aber kurz vor dem Ziel selbst verbaut mit deinen ersten beiden Kommentaren.
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.
### 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.
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
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
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...
Grüße
Biber
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...
Grüße
Biber
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:
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
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.
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