0

select :=> das ist zu viel für mich

Irgendwie wollen meine Hirnwindungen hier nicht mitmachen:

Ich habe eine Tabelle mit Lagerbeständen einzelner SKU

Ich habe mit 

select 'Lagerbestände' where Datum >= myStartdate and Datum <= myEnddate

Die Datensätze bereits auf Datumsebene eingegrenzt. Aber, jede SKU hat in diesem Datumsbereich etliche (nämlich) Tageslagerbestände, und ich benötige je SKU nur den höchsten, also Spitzenwert.

Hab schon einiges mit "for i" usw. versucht, aber irgendwie ist alles Murks was ich zustande gebracht habe.

Am Ende benötige ich die Summe aller Höchstwerte.

Wie komme ich da weiter?

Vielen Dank schon mal.

19 Antworten

null
    • mirko3
    • vor 1 Jahr
    • Gemeldet - anzeigen

    Hi Arwin. Versuche mal so. Mirko

    let allDat := unique((select 'Lagerbestände')[myStartdate <= Datum and Datum <= myEnddate].Datum);
    sum(for i in allDat do
            for j in select 'Lagerbestände' do
                let allSKUonDate := (select 'Lagerbestände')[Datum = i].SKU;
                if contains(allSKUonDate, j.SKU) and j.SKU = max(allSKUonDate) then
                    j.SKU
                end
            end
        end)
    
      • Arwin_Dustdar.1
      • vor 1 Jahr
      • Gemeldet - anzeigen

      Hallo @Mirko  vielen Dank, aber das führt offenbar in eine Endlosschleife oder so. Ninox bricht jedenfalls zusammen. :)

      Wenn ich versuche dein Snippet zu verstehen, dann holst du in Zeile 1 mit unique() doch bereits nur 1 Datensatz je Datum, richtig? Oder was wird da eingegrenzt?
       

       

      • mirko3
      • vor 1 Jahr
      • Gemeldet - anzeigen

       Da sind noch Fehler gewesen. Beim Nachdenken kam jetzt das heraus.

      let allDat := unique((select 'Lagerbestände')[myStartdate <= Datum and Datum <= myEnddate].Datum);
      sum(for i in allDat do
              max(for j in (select 'Lagerbestände')[Datum = i] do
                      j.SKU
                  end)
          end)
      

      Du iterierst über ein Datum-Array (Zeile 1) und bildest dabei ein Array der Maximalwerte, welches summiert wird. Mirko

    • mirko3
    • vor 1 Jahr
    • Gemeldet - anzeigen

    ...oder noch kürzer

    let allDat := unique((select 'Lagerbestände')[myStartdate <= Datum and Datum <= myEnddate].Datum);
    sum(for i in allDat do
            max((select 'Lagerbestände')[Datum = i].SKU)
        end)
    
      • Arwin_Dustdar.1
      • vor 1 Jahr
      • Gemeldet - anzeigen

       vielen Dank. Irgendwo ist immer noch der Wurm drin. Ninox bleibt schon mal stabil. Das ist schon mal gut. Aber als Ergebnis kommt bei mir 0.

      Ich habe vielleicht nicht gut beschrieben, wie die Tabellenstruktur ist. Es gibt ein Feld mit den Lagerbeständen (PFOWN). 

      Wenn ich jetzt zeitlich eingrenze, z.B. Monat Mai, dann hat jede SKU 31 Zeile Bestand, eine Zeile mit Bestand für jeden Tag. Wenn ich also 100 SKU habe, sind das 3100 Zeilen, die ich selektiere.

      Aus diesen 3100 Zeilen will ich dann die 100 Zeilen haben, in denen je SKU der höchste Wert im Feld PFOWN stand, und dann daraus die Summe bilden. 

      Da muss doch im Code noch irgendetwas ergänzt werden, oder? Ich kann das nicht erkennen, leider. 

      allDat ist doch die Selektion des Datumsbereichs, also z.B. alle Datensätze mit Datum Mai, richtig?

      Jetzt sind da 3100 Datensätze drin, 100 für jede SKU, und von diesen 3100 muss für jede unique SKU nur der Datenbestand für die Summierung genommen werden, der unter seinen (SKU) der mit dem höchsten Wert ist.

      Wenn eine SKU z.B. am 10.05. den höchsten Wert hatte, muss dieser Datensatz für die Summierung herangezogen werden, bei der nächsten war es vielleicht der 25.05. usw.

      • mirko3
      • vor 1 Jahr
      • Gemeldet - anzeigen

       Ja, das ist doch eine andere Zusammensetzung im Datenmodell als ich dachte. 

      Ich dachte folgendermaßen:

      Tabelle: Lagerbestände

      Zahlenfeld?: SKU 

      Datumfeld: Datum

      Jetzt neu: PFOWN, wahrscheinlich Zahlenfeld.

      Meine Überlegung war folgende. allDat liefert Dir alle Daten, die Du mit myStartdate und myEnddate eingegrenzt hast. Durch unique() ist es jeweils nur einmal vorhanden, falls Daten mehrfach vorhanden sind. 

      Über dieses Array iterierst Du nun und suchst in der Tabelle 'Lagerbestände' das Maximum von SKU des Arrays zu jedem Datum. Schlussendlich die Summe dieses Arrays.

      Das wird natürlich ein falsches Ergebnis bringen, da ich von dem Feld "PFOWN" nichts wusste und es jetzt auch noch nicht ganz einordnen kann. 

      Besteht denn da noch eine Verknüpfung? Ist pro Tag EIN Bestand mit MEHREREN SKU, oder umgedreht? Was heißt den SKU ausgesprochen? Gruß Mirko

      • Arwin_Dustdar.1
      • vor 1 Jahr
      • Gemeldet - anzeigen

       ja sorry, das war von mir nicht so glücklich beschrieben.

      Alle Daten sind in der einen Tabelle "Lagerbestände", keine Verknüpfungen. SKU steht für Stock Keeping Unit, und entspricht der Artikelnummer.

      Ein Datensatz in "Lagerbestände" enthält vereinfacht die Felder

      Datum | SKU | PFOWN       =>> übersetzt (Datum | Artikelnummer | Bestand)

      in PFOWN ist dann als Zahlfeld der Bestand des entsprechenden Tages (Datum) für die SKU

      Und für jeden Kalendertag hat jede SKU einen Datensatz mit seinem Lagerbestand.

      Ist pro Tag EIN Bestand mit MEHREREN SKU, oder umgedreht? 
       

      Es ist pro SKU und Tag ein Datensatz (Bestand) da. 

      Also bei 100 SKU sind es für 1 Kalendertag 100 Datensätze, für 31 Kalendertage 3100 Datensätze, ergo Bestände.

      Bei deinem letzten Code, hatte ich auch das SKU Feld als Bestandsfeld verstanden, wäre also entsprechend PFOWN, aber es müsste vorher noch der Teil rein, der Ninox sagt, finde unter den 31 Werten je SKU den jeweils höchsten.

      Ich bastele mal eben eine Beispieldatenbank 

    • mirko3
    • vor 1 Jahr
    • Gemeldet - anzeigen

    ...P.S. Notfalls eine Dummydatei mit einer paar Dummydaten für mich Dummy hochladen ;-)

      • Arwin_Dustdar.1
      • vor 1 Jahr
      • Gemeldet - anzeigen

       hier wäre eine Beispieldatei. Das Ergebnis der Abfrage wäre nach meiner Berechnung

       +      1.023,000000 

       +        224,000000 

       +        776,000000 

       +        566,000000 

       ------------------- 

       +      2.589,000000 

      Vielen Dank nochmal für deine Hilfestellung

    • mirko3
    • vor 1 Jahr
    • Gemeldet - anzeigen

    Bei mir sind die jeweils höchsten Werte eines Tages: 234+232+1023+776=2265?

    • mirko3
    • vor 1 Jahr
    • Gemeldet - anzeigen

    Für Deine ursprüngliche Tabelle kannst Du ja mal folgendes austesten:

    do as server
        let myStartdate := date(2023, 6, 1);
        let myEnddate := date(2023, 6, 31);
        let allDat := unique((select 'Lagerbestände')[myStartdate <= Datum and Datum <= myEnddate].Datum);
        sum(for i in allDat do
                max((select 'Lagerbestände')[Datum = i].PFOWN)
            end)
    end
    

    Ich schlafe jetzt erstmal darüber ;-). 

      • Arwin_Dustdar.1
      • vor 1 Jahr
      • Gemeldet - anzeigen

       

      Für Deine ursprüngliche Tabelle kannst Du ja mal folgendes austesten:

      Das habe ich mal gemacht, und es wird zumindest mal eine Zahl ausgegeben. Scheint mir recht groß, aber muss ich noch genauer prüfen. Bin jetzt auch erst mal müde. Vielen Dank für die Mithilfe und gute Nacht. :)

      ...Ich poste mal hier die Bilder die zeigen, wieso ich auf 2,589 Einheiten komme..

    • mirko3
    • vor 1 Jahr
    • Gemeldet - anzeigen

    Moin.

    • mirko3
    • vor 1 Jahr
    • Gemeldet - anzeigen

    Hi Arwin. Sagen wir Datum von 1.5.23 bis 30.06.23 und SKU = M4000.

    Mai-Maximum 300, Juni-Maximum 200.

    Sollen diese addiert werden (500) oder willst Du nur das Maximum von Mai und Juni (300) für die SKU =M4000? Oder soll es grundsätzlich nur eine Monatsstatistik werden?

      • Arwin_Dustdar.1
      • vor 1 Jahr
      • Gemeldet - anzeigen

       Guten Morgen Mirko, erst mal wieder vielen Dank für deine Mühe. 🙂

      In deiner Datenbank BeständeM2 ist das Ergebnis korrekt. Das scheint also die richtige Formel zu sein.

      Ich muss das sowieso auf einen Button legen, weil diese Abfrage die Performance deutlich drückt, und ich sogar ein paar Fehler hatte gestern Nacht, mit parallel laufenden API calls. 

      Ich beschreibe nochmal, was die Challenge ist:

      Ich bekomme eine Rechnung eines Dienstleisters, die bezieht sich auf einen Zeitraum (Monat) und enthält unter anderem Kosten für Lagerhaltung.

      Um nun die Entwicklung dieser Lagerhaltungskosten zu überwachen, habe ich mir überlegt, die im betreffenden Zeitraum je SKU maximal gelagerte Menge heranzuziehen, und aus der Summe aller SKU Maximallagermengen einen Quotienten zu ermitteln, indem ich die Kosten der Lagerhaltung auf alle Einheiten umlege.

      Um diesen Quotienten zu ermitteln, benötige ich die Summe der Max Mengen je SKU eines Zeitraumes.

      Konkret auf deine Frage:
      Nicht die Summe einer SKU über mehrere Zeiträume wird benötigt. Ich brauche die Höchstwerte aller SKUs in einem Monatsabschnitt.

      Da die Felder in der Tabelle "Eingangsrechnungen" stehen, wird dieser Zeitraum bereits über die an der Rechnung definierte Periode, z.B. "05-23" mit folgendem Script:
       

      let myStartdate := date(number(20 + substr(Periode, 3, 4)), number(substr(Periode, 0, 2)), 1);
          let myEnddate := date(number(20 + substr(Periode, 3, 4)), number(substr(Periode, 0, 2)) + 1, 0);
      

      So wie ich es sehe, sollte es mit deinem Script also klappen. 

      Ich probiere das jetzt mal, und melde mich wieder.

      • Arwin_Dustdar.1
      • vor 1 Jahr
      • Gemeldet - anzeigen

       so, das sieht gut aus. Soweit ich das prüfen kann, liefert dein Skript den gewünschten Wert.  

      Mir ist nur aufgefallen, dass der Befehl "do as server" möglicherweise die Performance ziemlich drücken kann. 

      Jedenfalls habe ich mit "do as server" gefühlte 30 Sekunden Scriptlaufzeit, ohne sind es eher 3-4. Kann das sein?

      Dein Skript entspricht jedenfalls der angedachten Anwendung. Im Button untergebracht, hat es auch keinen nennenswerten Einfluß auf die Performance.

      Vielen Dank für die Hilfe.

      Wenn ich statt des Höchstwertes einer SKU lieber den Mittelwert nehmen würde, wie würde ich den Code dann ändern? mit avg statt max?

      let allDat := unique((select Lagerbestand)[myStartdate <= Datum and Datum <= myEnddate].SKU);
          sum(for i in allDat do
                  avg((select Lagerbestand)[SKU = i].PFOWN)
              end)
      
      • Arwin_Dustdar.1
      • vor 1 Jahr
      • Gemeldet - anzeigen

      Ich habe es gerade ausprobiert.

      Ist ganz cool, mit avg, kommt dann der Mittelwert. 

      Vielen Dan Mirko.

    • mirko3
    • vor 1 Jahr
    • Gemeldet - anzeigen

    Freut mich, dass es dann doch noch gut wurde. Ich denke, dass auch das zweite select zeitlich noch eingegrenzt werden muss um fehlerhafte Berechnungen zu vermeiden. Ich habe es hier mal in ein Dashboard gelegt. Vielleicht kannst Du es ja noch gebrauchen. LG Mirko

    let allDat := unique((select Lagerbestand)[myStartdate <= Datum and Datum <= myEnddate].SKU);
        sum(for i in allDat do
                avg((select Lagerbestand)[myStartdate <= Datum and Datum <= myEnddate and SKU = i].PFOWN)
            end)
    
      • Arwin_Dustdar.1
      • vor 1 Jahr
      • Gemeldet - anzeigen

       Danke, eingebaut. :)