Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

The Power BI Data Visualization World Championships is back! Get ahead of the game and start preparing now! Learn more

Reply
lud_ex
Regular Visitor

Beschleunigung meines M-Code

Hallo  

Wer kann mir helfen mein bisherigen M-Code zu beschleunigen. Besonders langsam wird es ab der KE() Funktion beim Aktualisieren. Wäre euch sehr dankbar wenn jemanden helfen könnte: Her der erste Teil vom Code

let
    Sj = 2024,
    Ej = Date.Year(DateTime.LocalNow()) + 4,


    BO = (Y as number) as date =>
        let
            A = Number.Mod(Y,19), B = Number.IntegerDivide(Y,100), C = Number.Mod(Y,100),
            D = Number.IntegerDivide(B,4), E = Number.Mod(B,4),
            F = Number.IntegerDivide(B+8,25), G = Number.IntegerDivide(B-F+1,3),
            H = Number.Mod(19*A + B - D - G + 15,30),
            I = Number.IntegerDivide(C,4), J = Number.Mod(C,4),
            K = Number.Mod(32 + 2*E + 2*I - H - J,7),
            L = Number.IntegerDivide(A + 11*H + 22*K,451),
            M = Number.IntegerDivide(H + K - 7*L + 114,31),
            N = Number.Mod(H + K - 7*L + 114,31)+1
        in
            #date(Y,M,N),

    BOList = List.Transform({Sj..Ej}, each BO(_)),

    HD = () =>
        let
            L = List.Transform(
                    {Sj..Ej},
                    (Y) =>
                        let O = BOList{Y - Sj}
                        in {
                            #date(Y,1,1), #date(Y,5,1), #date(Y,10,3), #date(Y,11,1),
                            #date(Y,12,24), #date(Y,12,25), #date(Y,12,26), #date(Y,12,31),
                            O, Date.AddDays(O,-2), Date.AddDays(O,1), Date.AddDays(O,39),
                            Date.AddDays(O,49), Date.AddDays(O,50), Date.AddDays(O,60)
                        }
                ),
            FL = List.Combine(L),
            FN = List.Transform(FL, each Date.ToText(_, "yyyy-MM-dd"))
        in
            Record.FromList(FL, FN),



H0 = HD(),

    // Datumstabelle
    DT = () => List.Dates(#date(Sj,1,1), Duration.Days(#date(Ej,12,31) - #date(Sj,1,1)) + 1, #duration(1,0,0,0)),
    T0 = Table.FromList(DT(), Splitter.SplitByNothing(), {"Datum"}),

    // Urlaubstabelle
    U0 = Excel.CurrentWorkbook(){[Name="tblUrlaub"]}[Content],
    UT =
        let
            T = Table.TransformColumnTypes(U0, {{"Startdatum", type date}, {"Enddatum", type date}}),
            E = Table.ExpandListColumn(
                    Table.AddColumn(
                        T, "Bd",
                        each List.Dates([Startdatum], Duration.Days([Enddatum] - [Startdatum]) + 1, #duration(1,0,0,0))
                    ),
                    "Bd"
                ),
            C = Table.SelectColumns(E, {"Bd", "Mitarbeiter", "Art der Abwesenheit"}),
            F = Table.SelectRows(
                    C,
                    each [Art der Abwesenheit] = "W" or (
                        ([Art der Abwesenheit] = "U" or [Art der Abwesenheit] = "K")
                        and Date.DayOfWeek([Bd], Day.Monday) <= 4
                        and not Record.HasFields(H0, Date.ToText([Bd], "yyyy-MM-dd"))
                    )
                ),
            G = Table.Group(F, {"Bd", "Mitarbeiter"}, {{"Art", each List.First([Art der Abwesenheit]), type text}})
        in
            Table.TransformColumnTypes(
                Table.Pivot(G, List.Distinct(U0[Mitarbeiter]), "Mitarbeiter", "Art"),
                {{"Bd", type date}}
            ),

    // Join
    A0 = Table.Join(T0, "Datum", UT, "Bd", JoinKind.LeftOuter),

 // Wochenstruktur einmal pro Datum berechnen
    Fd = (dt as date) as record =>
        Record.Combine(
            List.Transform(
                List.TransformMany(
                    {"Mo","Di","Mi","Do","Fr","Sa"},
                    (tag) => {"E","Z","D","V","F"},
                    (tag, p) =>
                        let v = (Date.ToText(dt, "ddd", "de-DE") = tag)
                                and (Number.IntegerDivide(Date.Day(dt)-1, 7) + 1 =
                                     List.PositionOf({"E","Z","D","V","F"}, p) + 1)
                        in [Name = p & tag, Value = v]
                ),
                (r) => Record.FromList({r[Value]}, {r[Name]})
            )
        ),

    A1 = Table.AddColumn(A0, "Fd", each Fd([Datum])),



   RC = List.Transform(
    Table.ToRecords(A0),
    each let in [
        Datum = _[Datum],
        GV = Record.Combine({
            [
                Datum = _[Datum],
                Bd = _[Datum],
                J = Date.Year(_[Datum]),
                Mo = Date.ToText(_[Datum], "MMMM", "de-DE"),
                Wt = Date.ToText(_[Datum], "ddd", "de-DE"),
                WiM = Number.IntegerDivide(Date.Day(_[Datum])-1, 7) + 1,
                Ft = Record.HasFields(H0, Date.ToText(_[Datum], "yyyy-MM-dd")),   // <<< hier statt HD()
                So = Date.ToText(_[Datum], "ddd", "de-DE") = "So"
            ],
            Fd(_[Datum]),
            [
                Mitarbeiter1 = Record.FieldOrDefault(_, "Mitarbeiter1"),
                Mitarbeiter2 = Record.FieldOrDefault(_, "Mitarbeiter2"),
                Mitarbeiter3 = Record.FieldOrDefault(_, "Mitarbeiter3"),
                Mitarbeiter4 = Record.FieldOrDefault(_, "Mitarbeiter4"),
                Mitarbeiter5 = Record.FieldOrDefault(_, "Mitarbeiter5")
            ]
        })
    ]
),
         
        
 Pl = () => let
        BM1 = Table.AddColumn(Table.FromRecords(RC),"Mitarbeiter1",each let in
            if [GV][Mitarbeiter1] <> null then [GV][Mitarbeiter1]                
                else if [GV][Mo] = "April" and ([GV][FDi] or [GV][ZDo]) then "HL"
                else if [GV][Mo] = "April" and [GV][EDo] then "HK"
                else if ((fields as list) as logical => List.AnyTrue(Record.ToList(Record.SelectFields([GV], fields, MissingField.Ignore
                        ))))({"Ft","ESa","ZSa","DSa","VSa","FSa","So"}) then "X"
                else if ((fields as list) as logical => List.AnyTrue(Record.ToList(Record.SelectFields([GV], fields, MissingField.Ignore
                        ))))({"EDi","ZDi","DDi","VDi","FDi","ZDo","DDo","VDo","FDo","EFr","DFr","VFr"}) then "HL"
                else if ((fields as list) as logical => List.AnyTrue(Record.ToList(Record.SelectFields([GV], fields, MissingField.Ignore
                        ))))({"EMo","FFr"}) then "HK"
                else if [GV][Wt] = "Mi" or ((fields as list) as logical => List.AnyTrue(Record.ToList(Record.SelectFields([GV], fields, 
                        MissingField.Ignore))))({"ZFr"}) then "Frei"
                else "HK"),

        BM2 = Table.AddColumn(BM1,"Mitarbeiter2",each let in
            if [GV][Mitarbeiter2] <> null then [GV][Mitarbeiter2]
                else if [GV][Mo] = "April" and [GV][FMi] then "HK + LK"
                else if [GV][Mo] = "Juli" and ([GV][FMi] or [GV][DMi] or [GV][VFr]) then "HK + LK"
                else if ((fields as list) as logical =>List.AnyTrue(Record.ToList(Record.SelectFields([GV], fields, MissingField.Ignore
                        ))))({"Ft","ESa","ZSa","DSa","VSa","FSa","So"}) then "X"
                else if ((fields as list) as logical =>List.AnyTrue(Record.ToList(Record.SelectFields([GV], fields, MissingField.Ignore
                        ))))({"ZMi","DMi","VMi","EMi","FMi","ZFr","VFr"}) then "HK + LK"
                else if ((fields as list) as logical =>List.AnyTrue(Record.ToList(Record.SelectFields([GV], fields, MissingField.Ignore
                        ))))({"EDi","DDi","EMi","DMi","VFr"}) then "HK"
                else if ((fields as list) as logical =>List.AnyTrue(Record.ToList(Record.SelectFields([GV], fields, MissingField.Ignore
                        ))))({"ZMi","VMi"}) then "HL"
                else if [GV][Wt] = "Do" or [GV][EFr] then "Frei"
                else if [GV][Wt] = "Mo" or ((fields as list) as logical =>List.AnyTrue(Record.ToList(Record.SelectFields([GV], fields, 
                        MissingField.Ignore))))({"DFr","FFr"}) then "L"
                else if [GV][Mo] = "Juli" and [GV][ZSa] then "HL"
                else "HK"),

        BM3 = Table.AddColumn(BM2,"Mitarbeiter3", each let in
            if [GV][Mitarbeiter3] <> null then [GV][Mitarbeiter3]
            else if (List.Contains(Record.FieldValues(HD()), Date.From([GV][Datum]))) or ((fields) => List.AnyTrue(Record.ToList(
                    Record.SelectFields([GV], fields))))({"Ft","ESa","ZSa","DSa","VSa","So"}) then "X"
            else if ((fields) => List.AnyTrue(Record.ToList(Record.SelectFields([GV], fields))))({"ZMi","VMi","ZDo","DDo","VDo","FDo",
                    "DFr", "EFr"}) then "HK"
            else if ((fields) => List.AnyTrue(Record.ToList(Record.SelectFields([GV], fields))))({"EMo","EMi","DMi","FMi","ZFr",
                    "FFr","FSa"}) then "HL"
            else if [GV][Wt] = "Di" or ((fields) => List.AnyTrue(Record.ToList(Record.SelectFields([GV], fields))))({"VFr"}) then 
                    "Frei"
            else "HL"),

        BM4 = Table.AddColumn(BM3, "Mitarbeiter4", each let in
            if [GV][Mitarbeiter4] <> null then [GV][Mitarbeiter4]
            else if (List.Contains(Record.FieldValues(HD()), Date.From([GV][Datum]))) or ( (fields) => List.AnyTrue(Record.ToList(
                    Record.SelectFields([GV], fields))))({"So","Ft","ESa","DSa","FSa"}) then "X"
            else if ((fields) => List.AnyTrue(Record.ToList(Record.SelectFields([GV], fields))))({"DMi","VFr"}) then "LK"
            else if [GV][Wt] = "Mo" or ((fields) => List.AnyTrue(Record.ToList(Record.SelectFields([GV], fields))))({"DFr","FFr"}) then 
                    "Frei"
            else if ((fields) => List.AnyTrue(Record.ToList(Record.SelectFields([GV], fields))))({"DDi","DFr","FFr"}) then "L"
            else if ((fields) => List.AnyTrue(Record.ToList(Record.SelectFields([GV], fields))))({"DMi","VFr","ZMi","VMi","FMi","EMi",
                    "ZFr"}) then "LK"
            else if ((fields) => List.AnyTrue(Record.ToList(Record.SelectFields([GV], fields))))({"ZSa","VSa"}) then "HL"
            else "L"),

        BM5 = Table.AddColumn(BM4,"Mitarbeiter5", each let in
                if Record.FieldOrDefault([GV], "Mitarbeiter5", null) <> null then Record.FieldOrDefault([GV], "Mitarbeiter5", null)
                else if (List.Contains(Record.FieldValues(HD()), Date.From([GV][Datum]))) or ((fields as list) as logical =>
                    List.AnyTrue(Record.ToList(Record.SelectFields([GV],fields,MissingField.Ignore))))({"Ft","ZSa","VSa","So"}) then"X"
                else if ((fields as list) as logical =>
                    List.AnyTrue(Record.ToList(Record.SelectFields([GV], fields, MissingField.Ignore))))({"ESa","DSa"})then"HL"
                else "Frei")in BM5,
            

 

12 REPLIES 12
ralf_anton
Helper II
Helper II

...ja stimmt... hatte ich zwischenzeitlich vergessen. M5 taucht auch in der Urlaubstabelle nicht auf...

Ich will das Ganze jetzt nicht neu aufsetzen, aber überleg doch mal kurz:

* Was brauchst Du? (Welche Daten brauchst Du am Ende wirklich)

* Wofür brauchst Du was? (Aufgabe)

* Wo brauchst Du was? (in welcher Abfrage)

* Und wann brauchst Du was? (Reihenfolge)

 

Die Wochentage und Feiertage brauchst Du zum Beispiel doch nur am Anfang, damit Du diese Zeilen sofort wieder löschen kannst. Und auch alle unnötigen Spalten (Wochentag, Feiertag).  Dann hättest Du schon mal nur die relevanten Tage und auch nur die einzig relevante Spalte (Datum). 

Darauf setzt Du einen Verweis in einer weiteren Abfrage, die Du mit den Abwesenheiten abgleichst und verknüpfst. Ganz am Ende kannst Du noch die KW Spalte hinzufügen, denn vorher brauchst Du die nicht. Also auch die sinnvolle Reihenfolge überdenken.Würde nur unnötige Rechenzeit beanspruchen. So musst Du an die Sache herangehen.

 

ralf_anton
Helper II
Helper II

Hi,

 

nicht die Auslagerung der Feiertags- und IsoKW Funktionen bringen den Zeitgewinn, sondern die funktionale Aufteilung der Aufgaben in separate Abfragen, für die immer nur die jeweils benötigten Zeilen und Spalten verwendet weren, die sich auf Verweise anderer verschlankter Abfagen beziehen und deren Ergebnisse am Ende miteinander verknüpft werden.

Ich habe mal die Zeiten Deiner Abfrage mit meiner verglichen. Bei gleicher Datengrundlage und Deinen Vorgaben braucht Deine Abfrage bei mir über 2 Minuten, meine nur 8 Sekunden. Die Vorstellungskraft wird durch die Praxis korrigiert...

Ergebnis sähe so aus:

Zeitplanung_Ergebnis.jpg

 

Optischer Unterschied zu Deiner Vorgabe: Wie oben schon erwähnt, sich überlappende Abwesenheiten werden in Spalte H gekennzeichnet. Mit Angabe des MA und Tages. Das sich Handlungsbedarf daraus ergibt ist erkennbar, aber welcher, das entzieht sich meiner Kenntnis.

Bezieht sich auf folgende Abwesenheitstabelle:

Abwesenheiten.jpg

 

PS: Mir fällt gerade auf, am 4.1. hat ja nur MA 5 Dienst, die anderen beiden (MA 3 oder 4) hätten ja gar keinen... Somit könnte einer davon den Dienst übernehmen. Aber welcher davon? Und was, wenn alle 3 am gleichen Tag frei hätten? Das sind allerdings Fragen, die vorher geklärt werden solten.

Hallo

Überscheidungen von Urlaub und Frei darf es nie geben, somit braucht es keine Abwesenheitsüberschneidungsdatei, Was sehr zwingend Wissen muss ist M5 bekommt kein Urlaub so von Ihm gewollt, er macht ja nur zweimal im Monat Samstag HL, der Rest ist immer Frei, M4 macht nur L von Montag bis Freitag außer Feiertagen und zweimal im Monat wenn M5 kein Dienst hat  Samstag HL.                 M4 hat Montag, M3 Dienstag, M2 Donnerstag, M1 Mittwoch Frei.  Frei und Urlaub darf immer nur einer haben, Hat M4 Frei oder Urlaub muss M2 L machen, M1, M2, M3 haben abwechselnd HK und HL von Monatg bis Freitag  außer an Feiertagen , es dürfen müssen nur 2 Mitarbeiter pro Tag Dienst haben sonst hat der andere Frei.  Mir ist immer noch nicht ganz klar welche müssen zwingend ausgelagert werden müssen und welche nicht das die Geschwindigkeit zum positiven ist.

ralf_anton
Helper II
Helper II

Gesundes neues Jahr!

hab mir das Ergebnis(!) Deiner Abfrage noch mal angeschaut, nicht den Code, das ist mir nach wie vor zu umständlich. Das Ergebnis scheint mir, jedenfalls nach Deiner bisherigen Beschreibung nach zu urteilen, fehlerbehaftet. Z. Bsp. ist der 24.12. kein Feiertag, dafür fehlen andere. Auch bekommt MA3 nicht wirklich jeden 5. Samstag einen Dienst zugeordnet. 

Zum Projekt allgemein: PQ ist ja kein Planungstool. PQ ist ja vielmehr für Auswertungen konzipiert. Für Planungen solltest Du Scheduler oder Power Automate verwenden. 

Zur Geschwindigkeit: Die lange Verarbeitungszeit hängt ziemlich sicher damit zusammen, dass Du jede, für das Endergebnis unnötige Spalte und Zeile vom Anfang bis zum Ende mit durchschleppst. Die Spalte Wochentag z. Bsp. ist doch nur dafür relevant, um Sonntage rauszufiltern oder die Samstagsdienste zu ermitteln.  Danach kann sie weg. Oder die ganzen Feiertagszeilen können auch raus. 

Bei den Abwesenheiten ist mir noch unklar, wie Du Überschneidungen behandelst. Schau ich mir auch nicht (im Code) an. Die allgemeine Informationslage ist mir insgesamt zu dünn, die Quelltabellenstrukturen vermutlich verbesserungswürdig.

Wenn Du Deinen Code in Aufgabenspezifische Abfragen aufteilst, erreichst Du erhebliche Zeitgewinne. Ich hab mal rumgespielt und das im Bild gezeigte Ergebnis durch Aufteilung des Codes in mehrere Unterabfragen in wenigen Sekunden erreicht. Das entspricht jetzt zwar nicht Deiner Vorgabe, zumal da noch etliche Fragen offen wären, aber der Zeitgewinn ist im Vergleich zu Deinen 35 Minuten, enorm. Na gut... ich hab nur 1 Jahr ausprobiert... :🙂

Hier mal mein Ergebnis:

Mein EndergebnisMein Endergebnis

 

 

Auch frohes neues Jahr.

Das war mir fast klar das das kommt mit den Feiertagen, mit Heiligabend und Silvester ist von mir so gewollt, die Feiertage die für mich in Frage kommen sind alle drin. Aber wie nun von dir Vorgeschlagen die Funktionen ganz auszulagern in eine extra Abrage kann ich auch mal ausprobieren, kann mir aber nicht vorstellen das dies so eine große Minderung an Zeit bringt., Aber werde es ausprobieren.

ralf_anton
Helper II
Helper II

...schon klar, aber vergleiche doch bitte mal Deinen Abschnitt in List.Accumulate mit diesem:

 

                  List.Accumulate(
                        {
                            each 
                            //Mitarbeiter1 zusammenfassen
                            if _[Mitarbeiter1] = "U" then 
                                if _[Mitarbeiter4] = "Frei" then 
                                    Record.TransformFields(_, {{"Mitarbeiter4", each "L"}}) 
                                else if List.Contains({"HK","HK + LK"}, _[Mitarbeiter2]) then 
                                    Record.TransformFields(_, {{"Mitarbeiter3", each "HL"}}) 
                                else if _[Mitarbeiter3] = "HL" then 
                                    Record.TransformFields(_, {{"Mitarbeiter2", each "HK"}}) 
                                else if _[Mitarbeiter4] = "LK" then 
                                    Record.TransformFields(_, {{"Mitarbeiter2", each "HK + LK"}}) 
                                else if (try Text.Upper(Text.Trim(r[GV][Wt])) otherwise null) = "DI" then 
                                _ & [Mitarbeiter2 = "HL", Mitarbeiter3 = "HK"] 
                                else if Text.Start(Date.DayOfWeekName(r[Datum], "de-DE"), 2) = "Do" then 
                                    Record.TransformFields(_, {{"Mitarbeiter2", each "HL"}, {"Mitarbeiter3", each "HK"}}) 
                                else _
                            //Das gleiche hier mit Mitarbeiter4
                            else if _[Mitarbeiter4] = "U"
                                then Record.TransformFields(_, {{"Mitarbeiter2", each "L"}}) else _,

                            each if _[Mitarbeiter4] = "U" and _[Mitarbeiter3] = "Frei"
                                then Record.TransformFields(_, {{"Mitarbeiter3", each "HK"}}) else _,

                            each if _[Mitarbeiter4] = "U" and _[Mitarbeiter1] = "Frei"
                                then Record.TransformFields(_, {{"Mitarbeiter1", each "HK"}}) else _,

                            each if _[Mitarbeiter4] = "U" and _[Mitarbeiter3] = "W"
                                then Record.TransformFields(_, {{"Mitarbeiter4", each "L"}}) else _,

 

Du prüfst 6 mal auf MA1 (mit jeweils anderen Bedingungen). Wie gesagt, wenn MA nicht MA1 ist, dann muss ich das nicht 6 x prüfen. Und das für jeden dieser tausenden Datensätze. Da reicht 1 x....

MA4 hab ich im Bsp. nicht angepasst... zum besseren Vergleich.

Da gibt es im restlichen Code sicher noch mehr solcher unnötigen Prüfungsschritte., da musst Du schon mal selbst schauen...

 

Und weshalb machst Du das für 6 Jahre? 2024 und bald auch 2025 sind Geschichte und völlig irrelevant für eine Planung und wer weiß heute schon, wann er in 4 Jahren Urlaub nimmt? 

 

Hallo 

Vielen dank für deine Hilfe, habe das Ganze nun schafft so um zubauen wie von dir vorgeschlagen, hat es gedauert aber geschafft. Leider hat dies nicht den gewünschten Geschwindigkeit Erfolg gezeigt, habe mal genauer auf meiner Uhr geschaut, die Aktualisierung nach dieser Optimierung immer 35 Minuten.                   Weis denn jemanden noch einen Vorschlag wie ich das besser machen könnte, auf ein Jahr begrenzen ist keine Option für mich??

ralf_anton
Helper II
Helper II

Hi,

 

wer soll sich denn da durchwursteln? Wäre besser gewesen, Du hättest eine Beispieldatei (oder einen Link auf eine) gepostet. Egal... was mir auf einen schnellen Blick aufgefallen ist, in der KE Funktion prüfst Du in Accumulate jeden MA zig mal in Verbindung mit and.  Wenn Du auf die and Verknüpfung verzichtest und die Bedingungen etwas umstellst, sollte das schon erheblichen Zeitgewinn bringen. Beispiel:

if _[Mitarbeiter1] = "U" then 
	if _[Mitarbeiter4] = „Frei“ then
			tu dies…
	else if List.Contains({"HK","HK + LK"}, _[Mitarbeiter2])
                                then 
			tu das… 
	else 
			tu was anderes…
else if _[Mitarbeiter4] = "U" then 
	if ….
		….
		…

else  

 

Hallo   danke für die schnelle Antwort.  Ich würde gerne die Datei hochladen nur weiß ich nicht wie ich das mache.  In dieser Datei sind nur zwei Tabellen zu sehen (

eine Urlaubsdatei mit den Spalten (Mitarbeiter, Startdatum, Enddatum , Art der Abwesenheit)

und eine Mitarbeiterdatei mit Spalten ( Mitarbeiter, Name) mehr habe ich nicht in der Datei , den gesamten bisherigen Code habe ich ja schon gezeigt. 

...ok... Datei hochladen scheint hier wirklich nicht zu gehen, aber ein Link auf eine Cloud ginge schon. Hab jetzt die beiden Tabellen mal selbst erstellt... da Du unglücklicherweise Deinen M-Code aber so erstellt hast, dass keine Einzelschritte erkennbar sind (sind ja fast nur Funktionen), motiviert mich das nicht gerade dazu, nach potentiellen Verbesserungen zu suchen.

Du kannst aber schon mal meinen Hinweis von oben umsetzen. Alle Mehrfachprüfungen vermeiden. 

Es ist nicht sinnvoll Mitarbeiter4 mehrmals daraufhin zu prüfen, ob er vielleicht Mitarbeiter1 und U oder Mitarbeiter1 und x oder Mitarbeiter1 mit ganz was anderem ist... und das alles gleich nochmal für Mitarbeiter2 und 3... 

Wenn Mitarbeiter nicht Mitarbeiter1 sondern Mitarbeiter4 ist, dann erübrigen sich alle nachfolgenden and Verknüpungen für Mitarbeiter1... dann kann ich gleich zum nächsten MA springen.

Hallo

Nochmals Danke für deine ehrliche Antwort. Die einzelnen Funktionen habe ich erstellt weil ich daraus mehr Geschwindigkeit erzielt habe. Wie schon gesagt der erste Teil vom Code läuft eigentlich sehr zügig, in diesem ersten Teil werden die Dienste so verteilt wie sie in Normalform sein müssen und für einigermaßen gleicher Verteilung der Stunden und freien Tagen.                    Jetzt kommt der der große Knackpunkt erst jetzt soll im zweiten Teil die Urlaubsdatei mit hinzu gezogen werden, hier darf nur einer U haben von den Mitarbeiter 1 bis 4, Mitarbeiter 5 taucht in der Urlaubsdatei nie auf und das ist so gewollt., als erschwernis kommt hinzu das nicht jeder jeden Dienst ausüben kann , deswiteren werden Samstagdienste auf Mitarbeiter 4 und 5 aufgeteilt, den fünften Samstag macht Mitarbeiter 3, Samstag , Sonntag und Feiertage sind keine Urlaubstage.                                                                                                                             Meine KE Funktion hat schon die ganzen Zweige drin, genau deshalb sind es soviele zu Berücksichtigen.                                                                                                                                 Noch weiß ich nicht wie man KE besser schreiben könnte,

lud_ex
Regular Visitor

Hier der zweite Teil:

KE = (eingabeTabelle as table) as table =>
            let
                result = Table.FromRecords(
                        List.Transform(
                        List.Positions(Table.ToRecords(eingabeTabelle)),
                        (i) =>
                let
                    r = Table.ToRecords(eingabeTabelle){i},
                    previous = if i > 0 then Table.ToRecords(eingabeTabelle){i - 1} else null
                in
                    List.Accumulate(
                        {
                            each if _[Mitarbeiter1] = "U" and _[Mitarbeiter4] = "Frei"
                                then Record.TransformFields(_, {{"Mitarbeiter4", each "L"}}) else _,

                            each if _[Mitarbeiter1] = "U" and List.Contains({"HK","HK + LK"}, _[Mitarbeiter2])
                                then Record.TransformFields(_, {{"Mitarbeiter3", each "HL"}}) else _,

                            each if _[Mitarbeiter1] = "U" and _[Mitarbeiter3] = "HL"
                                then Record.TransformFields(_, {{"Mitarbeiter2", each "HK"}}) else _,

                            each if _[Mitarbeiter1] = "U" and _[Mitarbeiter4] = "LK"
                                then Record.TransformFields(_, {{"Mitarbeiter2", each "HK + LK"}}) else _,

                            each if _[Mitarbeiter1] = "U" and (try Text.Upper(Text.Trim(r[GV][Wt])) otherwise null) = "DI"
                                then _ & [Mitarbeiter2 = "HL", Mitarbeiter3 = "HK"] else _,

                            each if _[Mitarbeiter1] = "U" and (Text.Start(Date.DayOfWeekName(r[Datum], "de-DE"), 2)) = "Do"
                                then Record.TransformFields(_, {{"Mitarbeiter2", each "HL"}, {"Mitarbeiter3", each "HK"}}) else _,

                            each if _[Mitarbeiter4] = "U"
                                then Record.TransformFields(_, {{"Mitarbeiter2", each "L"}}) else _,

                            each if _[Mitarbeiter4] = "U" and _[Mitarbeiter3] = "Frei"
                                then Record.TransformFields(_, {{"Mitarbeiter3", each "HK"}}) else _,

                            each if _[Mitarbeiter4] = "U" and _[Mitarbeiter1] = "Frei"
                                then Record.TransformFields(_, {{"Mitarbeiter1", each "HK"}}) else _,

                            each if _[Mitarbeiter4] = "U" and _[Mitarbeiter3] = "W"
                                then Record.TransformFields(_, {{"Mitarbeiter4", each "L"}}) else _,

                            each if previous <> null
                                    and Text.Start(Date.DayOfWeekName(previous[Datum], "de-DE"), 2) = "Fr"
                                    and previous[Mitarbeiter4] = "U"
                                    and Text.Start(Date.DayOfWeekName(r[Datum], "de-DE"), 2) = "Sa"
                                    and r[Mitarbeiter4] = "HL"
                                then Record.TransformFields(_, {{"Mitarbeiter2", each "HL"}, {"Mitarbeiter4", each "X"}}) else _,

                            each if previous <> null
                                    and Text.Start(Date.DayOfWeekName(previous[Datum], "de-DE"), 2) = "Fr"
                                    and previous[Mitarbeiter4] = "U"
                                    and Text.Start(Date.DayOfWeekName(r[Datum], "de-DE"), 2) = "Sa"
                                    and r[Mitarbeiter5] = "HL"
                                then Record.TransformFields(_, {{"Mitarbeiter3", each "HL"}, {"Mitarbeiter5", each "X"}}) else _,

                            each if previous <> null
                                    and Text.Start(Date.DayOfWeekName(previous[Datum], "de-DE"), 2) = "Fr"
                                    and previous[Mitarbeiter4] = "U"
                                    and Text.Start(Date.DayOfWeekName(r[Datum], "de-DE"), 2) = "Sa"
                                    and r[Mitarbeiter5] = "HL"
                                then Record.TransformFields(_, {{"Mitarbeiter3", each "HL"}, {"Mitarbeiter5", each "X"}})
                                else if Date.Month(r[Datum]) = 1
                                        and Date.DayOfWeek(r[Datum], Day.Monday) = 0
                                        and Date.Day(r[Datum]) <= 7
                                        and r[Mitarbeiter4] = "U" or (Date.Month(r[Datum]) = 1
                                        and Date.DayOfWeek(r[Datum], Day.Saturday) = 0
                                        and Date.Day(r[Datum]) <= 7
                                        and r[Mitarbeiter5] = "HL")
                                    then Record.TransformFields(_, {{"Mitarbeiter3", each "HL"}, {"Mitarbeiter5", each "X"}}) else _,

                            each if _[Mitarbeiter3] = "W" and _[Mitarbeiter1] = "HK"
                                then Record.TransformFields(_, {{"Mitarbeiter2", each "HL"}}) else _,

                            each if _[Mitarbeiter3] = "W" and _[Mitarbeiter1] = "HL"
                                then Record.TransformFields(_, {{"Mitarbeiter2", each "HK"}}) else _,

                            each if _[Mitarbeiter3] = "W" and _[Mitarbeiter1] = "Frei"
                                then Record.TransformFields(_, {{"Mitarbeiter1", each "HK"}}) else _,

                            each if _[Mitarbeiter3] = "W" and _[Mitarbeiter4] = "LK"
                                then Record.TransformFields(_, {{"Mitarbeiter2", each "HK + LK"}}) else _,

                            each if (try Text.Upper(Text.Trim(r[GV][Wt])) otherwise null) = "FR" and previous <> null and Text.Upper
                                    (Text.Trim(previous[GV][Wt])) = "DO" and previous[Mitarbeiter3] = "W"
                                then Record.TransformFields(_, {{"Mitarbeiter3", each "Frei"}, {"Mitarbeiter4", each "L"}}) else _,

                            each if _[Mitarbeiter3] = "Frei" and _[Mitarbeiter1] = "HK"
                                then Record.TransformFields(_, {{"Mitarbeiter2", each "HL"}}) else _,

                            each if _[Mitarbeiter3] = "Frei" and _[Mitarbeiter1] = "HL" and _[Mitarbeiter2] = "L"
                                then Record.TransformFields(_, {{"Mitarbeiter2", each "HK"}}) else _,

                            each if _[Mitarbeiter3] = "U" and _[Mitarbeiter4] = "Frei"
                                then Record.TransformFields(_, {{"Mitarbeiter4", each "L"}}) else _,

                            each if _[Mitarbeiter3] = "U" and _[Mitarbeiter1] = "Frei"
                                then Record.TransformFields(_, {{"Mitarbeiter1", each "HK"}}) else _,

                            each if _[Mitarbeiter3] = "U" and _[Mitarbeiter2] = "Frei"
                                then Record.TransformFields(_, {{"Mitarbeiter2", each "HK"}}) else _,

                            each if _[Mitarbeiter3] = "U" and _[Mitarbeiter4] = "L"
                                then Record.TransformFields(_, {{"Mitarbeiter2", each "HL"}}) else _,

                            each if _[Mitarbeiter3] = "U" and _[Mitarbeiter1] = "HL"
                                then Record.TransformFields(_, {{"Mitarbeiter2", each "HK"}}) else _,

                            each if _[Mitarbeiter3] = "U" and _[Mitarbeiter4] = "LK"
                                then Record.TransformFields(_, {{"Mitarbeiter4", each "L"}}) else _,

                            each if _[Mitarbeiter3] = "U" and _[Mitarbeiter2] = "HK + LK"
                                then Record.TransformFields(_, {{"Mitarbeiter2", each "HL"}}) else _,

                            each if _[Mitarbeiter3] = "U" and (Date.DayOfWeek(DateTime.LocalNow())) = 5
                                then Record.TransformFields(_, {{"Mitarbeiter1", each "HL"}}) else _,

                            each if _[Mitarbeiter2] = "U" and List.Contains({"Frei","LK"}, _[Mitarbeiter4])
                                then Record.TransformFields(_, {{"Mitarbeiter4", each "L"}}) else _,

                            each if _[Mitarbeiter2] = "U" and (Text.Start(Date.DayOfWeekName(r[Datum], "de-DE"), 2)) = "Fr"
                                then Record.TransformFields(_, {{"Mitarbeiter1", each "HK"}, {"Mitarbeiter3", each "HL"}}) else _,

                            each if _[Mitarbeiter2] = "U" and _[Mitarbeiter1] = "Frei"
                                then Record.TransformFields(_, {{"Mitarbeiter1", each "HL"}}) else _,

                            each if _[Mitarbeiter2] = "U" and _[Mitarbeiter3] = "Frei"
                                then Record.TransformFields(_, {{"Mitarbeiter3", each "HK"}}) else _,

                            each if _[Mitarbeiter2] = "U" and (Text.Start(Date.DayOfWeekName(r[Datum], "de-DE"), 2)) = "Mi"
                                then Record.TransformFields(_, {{"Mitarbeiter1", each "HK"}, {"Mitarbeiter3", each "HL"}}) else _,

                            each if _[Mitarbeiter2] = "U" and (Text.Start(Date.DayOfWeekName(r[Datum], "de-DE"), 2)) = "Do"
                                then Record.TransformFields(_, {{"Mitarbeiter1", each "HL"}, {"Mitarbeiter3", each "HK"}}) else _,

                            each if _[Mitarbeiter1] = "K" and (Text.Start(Date.DayOfWeekName(r[Datum], "de-DE"), 2)) = "Mo"
                                then Record.TransformFields(_, {{"Mitarbeiter2", each "HL"}, {"Mitarbeiter3", each "HK"}, 
                                     {"Mitarbeiter4", each "L"}}) else _,

                            each if _[Mitarbeiter1] = "K" and (Text.Start(Date.DayOfWeekName(r[Datum], "de-DE"), 2)) = "Di"
                                then Record.TransformFields(_, {{"Mitarbeiter2", each "HK + LK"}, {"Mitarbeiter3", each "HL"}, 
                                     {"Mitarbeiter4", each "LK"}}) else _,

                            each if _[Mitarbeiter1] = "K" and (Text.Start(Date.DayOfWeekName(r[Datum], "de-DE"), 2)) = "Mi"
                                then Record.TransformFields(_, {{"Mitarbeiter2", each "HL"}, {"Mitarbeiter3", each "HK"}, 
                                     {"Mitarbeiter4", each "L"}}) else _,

                            each if _[Mitarbeiter1] = "K" and (Text.Start(Date.DayOfWeekName(r[Datum], "de-DE"), 2)) = "Do"
                                then Record.TransformFields(_, {{"Mitarbeiter2", each "HK"}, {"Mitarbeiter3", each "HL"}, 
                                     {"Mitarbeiter4", each "L"}}) else _,

                            each if _[Mitarbeiter1] = "K" and (Text.Start(Date.DayOfWeekName(r[Datum], "de-DE"), 2)) = "Fr"
                                then Record.TransformFields(_, {{"Mitarbeiter2", each "HL"}, {"Mitarbeiter3", each "HK"}, 
                                     {"Mitarbeiter4", each "L"}}) else _,

                            each if _[Mitarbeiter1] = "K" and _[Mitarbeiter4] = "Frei" and (Text.Start(Date.DayOfWeekName(r[Datum], 
                                    "de-DE"), 2)) = "Fr"
                                then Record.TransformFields(_, {{"Mitarbeiter2", each "HL"}, {"Mitarbeiter3", each "HK"}, 
                                     {"Mitarbeiter4", each "L"}}) else _,

                            each if _[Mitarbeiter1] = "Frei" and (Text.Start(Date.DayOfWeekName(r[Datum], "de-DE"), 2)) = "Mi"
                                then Record.TransformFields(_, {{"Mitarbeiter2", each "HK + LK"}, {"Mitarbeiter3", each "HL"}}) else _
                        },
                        r,
                        (state, rule) => rule(state))))
in
    result,
        CS = (lst as list) as list =>
            let
                n = List.Buffer(List.Transform(lst, each Number.From(_)))
            in
                List.Generate(() => [i = 0, s = 0],each [i] < List.Count(n),each [i = [i] + 1, s = [s] + n{[i]}],each [s]),

        IW = (d as date) as number => let in
             Number.IntegerDivide(Duration.Days(d -(Date.AddDays(#date(Date.Year(Date.AddDays(d, 3 -(Date.DayOfWeek(d, Day.Monday)))), 
             1, 4), -(Date.DayOfWeek(#date(Date.Year(Date.AddDays(d, 3 - (Date.DayOfWeek(d, Day.Monday)))), 1, 4), Day.Monday))))), 
             7) + 1,

       

R = () as table =>
let
    
    Source = KE(Pl()),
    B      = Table.AddIndexColumn(Source, "Ix", 0, 1, Int64.Type),

    U4 = List.Buffer(List.Transform(B[Mitarbeiter4], each if _ = "U" then 1 else 0)),
    C4 = CS(U4),

    recs = Table.ToRecords(B),

    U3PosList = List.Buffer(List.Accumulate(List.Positions(recs),[prevDate = null as nullable date, prevU = false, pos = -1, 
                out = {}],(s, i) =>
                    let
                        r = recs{i},
                        d = r[Datum],
                        isU = (r[Mitarbeiter3] = "U"),

                        prevDate = s[prevDate],

                        isConsecutiveWorkday = prevDate <> null and (d = Date.AddDays(prevDate, 1) or (Date.DayOfWeek(prevDate,
                                               Day.Monday) = 4 and d = Date.AddDays(prevDate, 3))),

                        newPos = if isU then if s[prevU] and isConsecutiveWorkday then s[pos] + 1 else 0 else null,

                        nextPos = if newPos = null then -1 else newPos
                    in
                        [prevDate = d,
                         prevU    = isU,
                         pos      = nextPos,
                         out      = s[out] & { newPos }])[out]),

    B2 = Table.AddColumn(B, "U3Pos", each U3PosList{[Ix]}, Int64.Type),

    R1 = Table.AddColumn(B2, "M1", each
        let
            i  = [Ix],
            z4 = C4{i}
        in
            if [Mitarbeiter3] = "U" then if Number.Mod([U3Pos], 2) = 0 then "HL" else "HK"
            else if [Mitarbeiter4] = "U" then if Number.Mod(z4, 2) = 0 then "HL" else "HK" else [Mitarbeiter1], type text),

    R2 = Table.AddColumn(R1, "M2", each if [Mitarbeiter3] = "U" then if Number.Mod([U3Pos], 2) = 0 then "HK" else "HL" else 
         [Mitarbeiter2], type text),

    R3 = Table.AddColumn(R2, "M3", each
        let
            i  = [Ix],
            z4 = C4{i}
        in
            if [Mitarbeiter4] = "U" then if Number.Mod(z4, 2) = 0 then "HK" else "HL" else [Mitarbeiter3], type text),

    Ergebnis = Table.RenameColumns(Table.RemoveColumns(R3, {"Ix", "U3Pos", "Mitarbeiter1", "Mitarbeiter2", "Mitarbeiter3"}),
               {{"M1", "Mitarbeiter1"}, {"M2", "Mitarbeiter2"}, {"M3", "Mitarbeiter3"}})
in
    Ergebnis,

        
    
        Ty = Table.TransformColumnTypes((Table.ExpandRecordColumn(R(),"GV",{"J","Mo","Wt"},{"J","Mo","Wt"})),{{"Datum", type date}}),
        KW = Table.AddColumn(Ty, "KW", each IW([Datum]), Int64.Type),
        MS = List.Buffer(List.Select(Table.ColumnNames(KW), each Text.StartsWith(_, "Mitarbeiter"))),
        Mi = List.Sort(MS,(a,b) =>Number.From(Text.AfterDelimiter(a,"Mitarbeiter")) -Number.From(Text.AfterDelimiter(b,"Mitarbeiter"))),
        Re = List.RemoveItems(Table.ColumnNames(KW), ({"J","KW","Mo","Datum","Wt"}) & Mi),
        Or = Table.ReorderColumns(KW, ({"J","KW","Mo","Datum","Wt"}) & Mi & Re),
        MN = Excel.CurrentWorkbook(){[Name="tblMitarbeiter"]}[Content][Name],
        PC = List.Min({List.Count(Mi), List.Count(MN)}),
        RP = List.Zip({List.FirstN(Mi, PC), List.FirstN(MN, PC)})
    in
        Table.Sort((Table.RenameColumns(Or, RP, MissingField.Ignore)), {{"Datum", Order.Ascending}})

Helpful resources

Announcements
Power BI DataViz World Championships

Power BI Dataviz World Championships

The Power BI Data Visualization World Championships is back! Get ahead of the game and start preparing now!

December 2025 Power BI Update Carousel

Power BI Monthly Update - December 2025

Check out the December 2025 Power BI Holiday Recap!

FabCon Atlanta 2026 carousel

FabCon Atlanta 2026

Join us at FabCon Atlanta, March 16-20, for the ultimate Fabric, Power BI, AI and SQL community-led event. Save $200 with code FABCOMM.