Oracle - aufeinanderfolgende Zeilen zusammenfassen

warface

Mitglied
Hallo,
ich hoffe ihr könnt mir weiter helfen.
ich habe eine Tabelle mit den folgenden Spalten
- Gruppe
- Name
- Datum
- Von
- bis
- Menge
und würde gerne die Einträge zusammenfassen solange die Datensätze auf einander folgen.

z.B.
Fest;Mustermann;20200312;900;1000;50
Fest;Mustermann;20200312;1000;1100;40
Fest;Mustermann;20200312;1100;1200;50
Fest;Mustermann;20200312;1210;1300;50
Fest;Mustermann;20200312;1300;1400;50

Ergebnis
Fest;Mustermann;20200312;900;1200;140
Fest;Mustermann;20200312;1210;1400;100

Ich hab es schon mal mit der Lead-Funktion probiert, da es aber auch 100+ Datensätze sein könnten, müsste ich ja eine ewig lange Abfrage bauen.
Gibt es da vielleicht ein bessere Lösung?
 

Zvoni

Erfahrenes Mitglied
Ich sehe hier kein Muster, wie sich das Resultat aufbauen soll, insbesondere nicht für die letzten beiden Spalten.
Ansonsten hat Oracle AFAIK die Funktion LISTAGG um Spalten zu einem String zu kombinieren
https://docs.oracle.com/cd/E11882_01/server.112/e41084/functions089.htm#SQLRF30030
EDIT: OK, ich glaube ich habs verstanden. Hinweis war "aufeinander folgen".
Solange Von und Bis (kombiniert mit Datum?) "direkt" aufeinander folgen (im Gegensatz zu Bis 1200 - Von 1210) soll die letzte Spalte summiert werden.
Au weia, dat wird ein Monster....
 
Zuletzt bearbeitet:

warface

Mitglied
Zvoni
genau, ich will ein bestimmtes Feld summieren so lange die Datensätze aufeinander folgen.
falls es hilft jeder Eintrag hat eine eindeutige ID

Ich hab das mal mit Lead probiert

CASE
WHEN BIS = LEAD(VON, 1) OVER (PARTITION BY gruppe,
name,
datum
ORDER BY
gruppe,
name,
datum,
von) /*next id*/
menge + LEAD(MENGE, 1) OVER (PARTITION BY gruppe,
name,
datum
ORDER BY
gruppe,
name,
datum,
von)
 

Zvoni

Erfahrenes Mitglied
hmm, hätte jetzt eher was in der Form
MIN(VON)
MAX(BIS)
SUM(Menge) ..... WHERE Bis=LEAD(Von,1) OVER (blablablabla) GROUP BY Gruppe, Name, Datum erwartet.

EDIT: Kenn mich in Oracle nicht aus. Deshalb weiss ich jetzt nicht ob mein Vergleich ins WHERE oder in eine HAVING muss/soll

EDIT: Bin mir nicht sicher, aber müsste das nicht mit einem INNER JOIN auf sich selbst gehen?

AIRCODE!

SQL:
SELECT T1.Gruppe, T1.Name, T1.Datum, Min(T1.Von), Max(T1.Bis), SUM(T1.Menge)
FROM Tabelle T1
INNER JOIN
Tabelle T2
ON
T1.Gruppe=T2.Gruppe AND
T1.Name=T2.Name AND
T1.Datum=T2.Datum AND
T1.Bis=T2.von
WHERE
Irgendwas
GROUP BY
T1.Gruppe,
T1.Name,
T1.Datum
 
Zuletzt bearbeitet:

warface

Mitglied
Zvoni, danke für deine Unterstützung.
Leider hat's damit nicht geklappt.
Ich habe aber inzwischen selber was gebaut, werde es morgen mal hier einfügen.
vielleicht habt Ihr noch Verbesserungen ;-)

Ich hab mit LAG und LEAD den ersten und den letzten Datensatz der zusammenhängenden Zeilen markiert und dass als Basis genutzt.
 

warface

Mitglied
so siehts bei mir aus,
Verbesserungen sind erwünscht :)

*EDIT*
hatte einen kleinen Denkfehler, nun funktionierts ;-)

SQL:
SELECT

    Gruppe,
    Name,
    Datum,
    von,
    bisX as bis,
    menge,
    /*Wenn das Ende-Kennzeichen = 'X' ist, wird die Menge der Datebsätze zwischen Von und BisX summiert*/
    CASE
        WHEN ende = 'X' THEN Menge
        ELSE (
        SELECT
            SUM(Menge)
        FROM
            Daten
        WHERE
            Gruppe = x.Gruppe
            AND Name = x.Name
            AND Datum = x.Datum
            AND von >= x.von
            AND bis <= x.bisX)
END AS Menge,
    Anfang,
    Ende
FROM
    (
    /*
    Wenn das Ende-Kennzeichen = 'X' ist wird Bis verwendet, ansonsten bis des Nachfolgers
    */
    SELECT
            Gruppe,
            Name,
            Datum,
            von,
            bis,
            menge,
            CASE
            WHEN ende = 'X' THEN bis
            ELSE LEAD(bis, 1) OVER (PARTITION BY Gruppe,Name,Datum ORDER BY Gruppe,Name,Datum)
            END AS bisX,
        Menge,
        Anfang,
        Ende
    FROM
(
    /*Es werden nur noch Anfang- und End-Buchungen ausgegeben */
    Select * from
        (
        /*
        Es wird ein Kennzeichen beim ersten und letzten Datensatz einer zusammenhängenden Kette gesetzt
        Wenn kein direkter Nachfolger(BIS=VON des Nachfolgers) exisitert wird 'X' in der Ende-Spalte gesetzt
        Wenn kein direkter Vorgänger(VON=BIS des Vorgängers) existiert wird 'X' in der Anfang-Spalte gesetzt
        */
        SELECT
            Gruppe,
            Name,
            Datum,
            von,
            bis,
            menge,
        CASE
                WHEN LAG(bis, 1) OVER (PARTITION BY Gruppe,Name,Datum
            ORDER BY Gruppe,Name,Datum) = von THEN ''
                ELSE 'X'
        END AS Anfang,
        CASE
                WHEN LEAD(von, 1) OVER (PARTITION BY Gruppe,Name,Datum
            ORDER BY Gruppe,Name,Datum) = bis THEN ''
                ELSE 'X'
        END AS Ende
        FROM
            DATEN
        ORDER BY
            1,
            2,
            3,
            4) where Anfang = 'X' or Ende = 'X') x
 
Zuletzt bearbeitet:

Neue Beiträge