Verschiedene Datumswerte analysieren und korrekt ausgeben

absoluter WAHNSINN!!!

Ich mach das jetzt analog mit allen anderen so weiter, sogar mit Grund des Ereigniswechsels! Ich bin absoult fassungslos.

Wenn das jetzt dann so in der Art klappt wie ich mir das vorstelle, wow.
Distinct ja, okay, kann bei vielen Datensätzen lange dauern, aber ich werte wenn einen Mitarbeiter oder einen Kunden, wo mehrere Mitarbeiter kommen können, aber meistens einfach.

Danke und schönes Wochenende schon mal, ich pack das vielleicht am Sonntag mal an, da solls regnen 🙃
 
Werbung:
Ja Performance kann schnell ein Thema werden, auch Window-Funktionen sind zwar effizient aber müssen ja auch was tun.

Das grundsätzliche Problem bei der Sache ist aber das du aus einer Zeile eine unbekannte Anzahl an Ergebniszeilen machen musst. Das kann tatsächlich nur mit mehreren Abfragen und UNION oder mit Joins oder mit CTE und Rekursion klappen. Also selbst wenn man eine noch so komplexe Logik mit CASE oder anderen Mitteln baut, man kommt nicht drum herum aus einer Zeile mehrere zu machen. Da liegt es nahe erstmal quasi zu normalisieren und das ist mit UNION zumindest logisch simpel.
 
kurzes Feedback für dich @ukulele:
Habe noch etwas in den Stammdaten angepasst gehabt, jetzt klappts es mit den "von" Werten einwandfrei. Ich arbeite jetzt daran, dass manche Werte auch enden können und damit eine neue Phase starten kann, beispielsweise ebvon kann mit ebbis enden und hat kein neuen Anfang, dann ist mit ebbis + 1 eine neue Phase.
 
es klappt wunderbar bisher, was aber passiert, das phasebis manchmal so lange geht, bis der Mitarbeiter wieder im Einsatz bei dem Kunden ist, also wenn ein anderer Kunde zwischen drin ist, wird das nicht unterbrochen, also einsatzbis ist maximum und phase darf nicht größer sein

*EDIT*

Code:
case     when COALESCE(lead(eventdate) OVER (PARTITION BY personalnr,kundennr ORDER BY eventdate::date) - interval '1 Day', einsatzbis)::date > einsatzbis
            then einsatzbis
            else COALESCE(lead(eventdate) OVER (PARTITION BY personalnr,kundennr ORDER BY eventdate::date) - interval '1 Day', einsatzbis)::date
        end as phasebis
 
Also ich verstehe nicht ganz was du meinst aber nochmal als Gedankenstütze:

zum Post #33

Ich habe in meinem UNION Teil einsatzvon und einsatzbis einfließen lassen, weil ich beide Datumswerte brauche, sonst weiß ich ja nicht, wann das Ende ist. Ich habe darüber hinaus nur tvon und stufevon gewählt, die läuten immer eine neue Phase ein. Ich habe auf tbis und stufebis verzichtet, weil die funktional abhängig vom jeweils nächsten Interval oder von einsatzbis sind. Gibt es z.B. ein tvon dann liegt das tbis entweder einen Tag vor dem nächsten tvon oder auf dem Tag einsatzbis. Es gibt daher keine Phase mehr dazwischen und ich brauche keine Unterbrechung.

Wenn du jetzt eine Spalte hast wo sagen wir tvon an Tag 2 passiert, tbis an Tag 4 und das nächste tvon erst wieder an Tag 7, dann müsste man die tvon Events gesondert aufführen damit eine Phase 2 bis 4, eine Phase 5 bis 6 und eine Phase 7 bis Ende dabei raus kommen. Die Funktionale Abhängigkeit von tbis läßt das aber in den Testdaten nicht zu, gibt es ein tbis für Tag 4, gibt es auch ein tvon für Tag 5.

Es kommt also sehr stark auf die logische Grundlage für deine Tabelle an. Wenn ebbis jetzt nicht diese Funktionale Abhängigkeit hat dann könnte es reichen für ebbis ebenfalls ein UNION anzuhängen, damit sollte eine Unterbrechung gewährleistet sein. Kann höchstens sein das wenn sie dann auf den selben Tag fällt wie das nächste ebvon, das dann eine ungewollte ein-Tages-Unterbrechung statt findet, das müsste man dann nochmal prüfen.

zum Post #34

Wenn Daten eines anderen Kunden relevant für eine Unterbrechung sind, dann muss man eventuell die komplette Betrachtung nicht auf Basis PARTITION BY personalnr und kundennr machen sondern nur nach personalnr. Das ist jetzt aber erstmal nur ein Denkansatz.
 
du hast Recht, ich habe beispielswese bei ebvon den Tag 1 und ebbis Tag 5, das ist eine phase, dann habe ich aber ebvon an Tag 6 wieder, ohne ein Ende, also Tag 6 bis einsatzbis. Er macht mir dann eine neue Phase mit ebbis mit Tag 5 bis Tag 5 und eine Phase mit Tag 6 bis einsatzbis.

Frage ist, ob ich das mit min/max gruppieren kann oder beim union eine Bedinung lege, dass ebzbis nur genommen wird, wenn das nachfolgende ebzvon ungleich ebzbis + 1 Tag ist.
 
auf den ersten Blick hat folgendes geholfen:

Code:
select     personalnr,
            kundennr,
            einsatzvon,
            einsatzbis,
            eventdate,
            eventtype
        FROM    (
            SELECT     personalnr,
                kundennr,
                einsatzvon,
                einsatzbis,
                ebvon,
                lag(ebvon) OVER (PARTITION BY personalnr,kundennr ORDER BY ebvon desc) - interval '1 Day' as ebvonminus,
                ebbis AS eventdate,
                'ebbis' AS eventtype
            FROM    rohdaten
            group by 1,2,3,4,5,7,8
            order by 1 asc, 2 asc, 3 desc, 5 desc, 8 desc
            ) t1
        WHERE   ebvonminus <> eventdate and eventdate is not null)
 
du hast Recht, ich habe beispielswese bei ebvon den Tag 1 und ebbis Tag 5, das ist eine phase, dann habe ich aber ebvon an Tag 6 wieder, ohne ein Ende, also Tag 6 bis einsatzbis. Er macht mir dann eine neue Phase mit ebbis mit Tag 5 bis Tag 5 und eine Phase mit Tag 6 bis einsatzbis.
Du lässt das "Event" ebbis einfach komplett außen vor, nur ebvon macht eine Unterbreuchung. Das würde in dem Fall genau das gewünschte Verhalten liefern. ebbis ist NUR relevant, wenn zwischen ebbis und dem nächsten ebvon eine Lücke von mehr als einen Tag sein kann.
 
Du lässt das "Event" ebbis einfach komplett außen vor, nur ebvon macht eine Unterbreuchung. Das würde in dem Fall genau das gewünschte Verhalten liefern. ebbis ist NUR relevant, wenn zwischen ebbis und dem nächsten ebvon eine Lücke von mehr als einen Tag sein kann.

fast richtig, es kann sein, dass ebbis endet und es nie wieder ein von gibt, dann benötige ich die phase, da es kein neues ebvon gibt.

Ich war gerade schön am Daten zusammentragen mit den neuen Phasen, dann fiel mir auf, dass ich stufe nicht richtig ausgewiesen bekomme, beispiel:

Phase geht von 01.03.2025 bis 17.06.2025
letzte Stufe beginnt am 18.12.2024

Ich konnte aber nicht den Wert der Stufe ermittelt, da der 18.12.2024 nicht zwischen den beiden Datumswerten liegt. Ich habe jetzt mit

Code:
case     when lag(t4.stufe::date) OVER (PARTITION BY p.personalnr, k.kundennr ORDER BY t4.stufe::date desc) is null
                then ep.einsatzbis::date
                else null
            end as stufebis

es so gelöst, das wenn Stufe keinen Nachfolger hat, dann wird Stufebis ausgegeben, sonst null, mal schauen ob dass das gewünscht ergebnis bringt

*Edit*

muss anderen weg finden, fensterfunktionen sind in join und where nicht zugelassen :-D
 
Zuletzt bearbeitet:
Tu das, solltest du nicht weiter kommen dann leg mal einen Demo-Fall komplett als Testdatensatz an. Da kann ich mich besser rein denken.
 
@ukulele mal ein kurzes Update:

stecke tatsächlich in den letzten Zügen. Geschwindigkeit ist auch noch unter einer Sekunde.

Was ich aber gerade an Problem habe, ist folgendes:

Ich habe eine Tabelle, auf die gehe ich mit einem left join.

Nach dem on der tabelle, sage ich direkt, dass ich nur gewisse Lohnarten möchte, beispielsweise Lohnart 1 und Lohnart 2

Im Statemant sage ich dann:

case when lohnart = 1 then preis else null end as eurolohnart1
case when lohnart = 2 then preis else null end as eurolohnart2

JEtzt bekomme ich aber zwei Datensätze angezeigt, einmal wo eurlohnart1 der preis angezeigt wird und einmal ist es null, das gleiche gilt für eurolohnart2.

Ich wollte nicht mit max() arbeiten, aber gibts ne Möglichkeit hierfür? Oder muss ich mehrere joins auf die Tabelle machen und dort immer nur die jeweiliige Lohnart nehmen?

Also
left join tabelle t1 on t1.lohnart = 1
left join tabelle t2 on t2.lohnart = 2
 
Also eine Möglichkeit wäre den Join so eng zu fassen das immer nur genau ein Datensatz gejont wird. Wenn du Werte aus zwei Datensätzen brauchst, machst du zwei Joins, das finde ich auch eleganter als CASE im SELECT-Teil.

Wenn du nur einen Wert brauchen würdest wäre das was anderes aber so finde ich das die beste Methode.
 
Das mit dem join ist so:
Ich brauche aus Tabelle Lohn den Preis von 15 Lohnarten. In der Tabelle ist es so, das jede Lohnart mit einem Datum versehen ist, wann diese gezahlt wurde.

Lohnart1 am 22.05.2022 mit 11€
Lohnart2 am 22.05.2022 mit 10€
Lohnart3 am 22.05.2022 mit 9€
Und so weiter

Ich möchte es dann so ausgewiesen bekommen, das lohnart1 eine Spalte ist, lohnart2 eine Spalte und Lohnart3 eine Spalte.

Im select mache ich dann
case when lohnart = 1 then preis Else null end
Case lohnart = 2 …

Dann bekomme ich in den jeweiligen Spalten aber dort ein null, wo die lohnart nicht dazugehört. Also wo in Spalte Lohnart2 was steht, ist bei Lohnart1 ein null und ein Datensatz weiter ist dieser dann gefüllt aber bei der anderen nicht.

Wenn ich jetzt 15x auf die gleiche Tabelle joine, mit den Filter der jeweiligen Lohnart, geht die Geschwindigkeit ganz schön hoch.
 
Werbung:
Wenn ich jetzt 15x auf die gleiche Tabelle joine, mit den Filter der jeweiligen Lohnart, geht die Geschwindigkeit ganz schön hoch.
Dein Datenmodell entspricht EAV (Entity Attribut Value) und da ist das mit mehreren Joins durchaus so gewollt. Die Join-Condition muss exakt sein, also es sollten nicht mehrere Zeilen durch einen Join entstehen und natürlich sind dann Indexe und Größe der Tabelle relevant aber eigentlich sollte das kein Problem sein.

Eventuell lohnt es sich, die Anfrage zu zerlegen oder irgendwas zusammen zu führen, das ist schwer zu sagen. Irgendwann ist man halt an einem Punkt wo die Auswertung zu mächtig wird, dann muss man sowas vielleicht als Auswertungsbestand erzeugen.
 
Zurück
Oben