Jörg: mysql Abfrage mit Teilsummen

Hallo,

ich habe eine Query, die in etwas so aussieht:

SELECT
    a.Datum,
	a.Std,
    m.Spalte1,
    m.Spalte2
FROM
    table1 a
JOIN table2 m ON
    a.ID = m.ID
WHERE
    ...
ORDER BY
    a.Datum ASC

Nun würde ich gerne die Stunden aus Tabelle1 tageweise addiert haben, aber dennoch alle Einzelwerte der jeweiligen Tage behalten.

Ungefähr so:

2021-03-01|3|..|..|...|
2021-03-01|1|..|..|...|
----------------------------
2021-03-01|4
----------------------------
2021-03-02|2|..|..|...|
...

Muss ich dazu php bemühen oder würde das auch in einer Query abfragbar sein?

Gruß, Jörg

  1. Entspricht …

    SELECT
        a.Datum,
    	a.Std,
        m.Spalte1,
        m.Spalte2
    FROM
        table1 a
    JOIN table2 m ON
        a.ID = m.ID
    WHERE
        ...
    SELECT
        a.Datum,
    	  a.Std,
        SUM() as Gesamt
        m.Spalte1,
        m.Spalte2
    FROM
        table1 a
    JOIN table2 m ON
        a.ID = m.ID
    WHERE
        ...
    GROUP BY
        a.Datum ASC
    ORDER BY
        a.Datum ASC
    

    Deinem Vorhaben?

    1. SUM(a.Std) as Gesamt
      

      natürlich...

    2. Hallo Raketen*,

      ich muss grad mal überlegen, was Du da machst. Auf den ersten Blick sah es aus, wie eine korrelierte Subquery, aber dann würde ein Komma fehlen und es wäre ein "where" zuviel, oder?

      Also mutmaße ich, dass Du folgende Query meinst?

      Also

      Entspricht …

      SELECT
          a.Datum,
      	  a.Std,
          SUM(a.Std) as Gesamt
          m.Spalte1,
          m.Spalte2
      FROM
          table1 a
      JOIN table2 m ON
          a.ID = m.ID
      WHERE
          ...
      GROUP BY
          a.Datum ASC
      ORDER BY
          a.Datum ASC
      

      Deinem Vorhaben?

      Meintest Du die Query so?

      Dann würde sie zwar die Std. addieren, aber mit gehen die Spalten 1+2 verloren.

      Oder habe ich Dich missverstanden?

      Jörg

      1. Dein Vorhaben wird wohl so nicht funktionieren, weil Du Datenzeilen unterschiedlicher Struktur in der Rückgabe haben willst.

        Ungefähr so:

        2021-03-01|3|..|..|...|
        2021-03-01|1|..|..|...|
        ----------------------------
        2021-03-01|4
        ----------------------------
        2021-03-02|2|..|..|...|
        ...
        
        1. Dein Vorhaben wird wohl so nicht funktionieren, weil Du Datenzeilen unterschiedlicher Struktur in der Rückgabe haben willst.

          Ungefähr so:

          2021-03-01|3|..|..|...|
          2021-03-01|1|..|..|...|
          ----------------------------
          2021-03-01|4
          ----------------------------
          2021-03-02|2|..|..|...|
          ...
          

          Hallo Raketen*,

          nein, ich war nur schreibfaul. Ob jetzt in der Ergebniszeile 3 Spalten mehr oder weniger aufgeführt sind, wäre egal, weil ich diese Spalten ja anschließend herauslassen könnte.

          Jörg

          1. Ob jetzt in der Ergebniszeile 3 Spalten mehr oder weniger aufgeführt sind, wäre egal, weil ich diese Spalten ja anschließend herauslassen könnte.

            Das klingt aber nach „kompliziert“ weil Du erst durch das neue Datum im Datensatz erfährst, dass der von eben die Summe war. Da wären wohl zwei Abfragen mit passender Ergebniszuordung simpler. Oder halt keine Summe aus der Datenbank sondern „aufaddieren“ in der Ergebnisabfrage und bei einem Datumswechsel stumpf erstmal Summe ausgeben, dann den neuen Ergebnissatz…

            1. Hallo Raketen*,

              Das klingt aber nach „kompliziert“ weil Du erst durch das neue Datum im Datensatz erfährst, dass der von eben die Summe war. Da wären wohl zwei Abfragen mit passender Ergebniszuordung simpler. Oder halt keine Summe aus der Datenbank sondern „aufaddieren“ in der Ergebnisabfrage und bei einem Datumswechsel stumpf erstmal Summe ausgeben, dann den neuen Ergebnissatz…

              Ich glaube, zweiteres wirds werden. Oder aber ich arbeite so vor, dass die Daten anders strukturiert abgefragt werden können. Das überlege ich gerade parallel.

              Jörg

  2. Hi,

    Ungefähr so:

    2021-03-01|3|..|..|...|
    2021-03-01|1|..|..|...|
    ----------------------------
    2021-03-01|4
    ----------------------------
    2021-03-02|2|..|..|...|
    ...
    

    Muss ich dazu php bemühen oder würde das auch in einer Query abfragbar sein?

    definiere eine Query ...

    Man könnte evtl was tricksen, indem man
    deine Query per Union mit einer anhand der Tage gruppierenden Query (mit entsprechend vielen null-Spalten auf die gleiche Spaltenzahl gebracht) verbindet.

    Also sowas (ungetestet):

    SELECT a.Datum, a.Std, m.Spalte1, m.Spalte2 FROM ...
    UNION
    SELECT a.Datum, SUM(a.Std), null, null FROM table1 a GROUP BY a.Datum, null, null, null
    

    evtl dann noch eine äußere Query, die die Spalten der inneren durchreicht, und dann für die Sortierung sorgt.

    cu,
    Andreas a/k/a MudGuard

    1. Hallo MudGuard,

      zwei Dumme, ein Gedanke 😂

      Aber Du musst UNION ALL nehmen, der einfache Union beinhaltet eine DISTINCT-Operation.

      Und der ORDER BY hintendran, damit die Teilsummen schön bei den Tageswerten stehen.

      Aber trotzdem: sowas geht für eine adhoc-Auswertung, nicht für schöne Reports.

      Rolf

      --
      sumpsi - posui - obstruxi
  3. Hallo Jörg,

    Muss ich dazu php bemühen

    Das, oder einen Reportgenerator.

    Grund 1: SQL ist ein Datenlieferant. Kein Datenaufbereiter. Der Versuch, mit SQL Mitteln die Darstellung der Daten zu „schönen“, kann gelegentlich gelingen, ist aber nicht der Sinn von SQL.

    Grund 2: Ein SELECT liefert entweder die Details oder eine Aggregation. Nicht beides auf einmal. Die Idee einer relationalen DB ist, dass alle Rows einer Table (und damit auch die Rows eines SELECT-Ergebnisses) inhaltlich ähnlich sind. Details vs Aggregation widerspricht dem.

    Eine Teilsumme in der Std-Spalte würde auch bedeuten, dass der Wert in dieser Spalte unterschiedliche Bedeutungen hat. Mal eine Stundenzahl (nehme ich an), mal die Summe der Stunden für diesen Tag. Automatische Folgefrage des kleinen Programmierers: Woran erkenne ich beim Lesen des Abfrageergebnisses, ob ich da Details oder eine Teilsumme vorliegen habe?

    Hinzu kommt der Raketenhinweis, dass die Struktur der Sätze verschieden ist. Die Teilsummen haben weniger Spalten als die Details.

    Mein eingangs genanntes „gelegentliches Gelingen“ könnte man über einen Union lösen - den ich jetzt hinschreibe, aber nicht teste.

    SELECT Datum, 'Summe: ' as Bedeutung, SUM(Std) as Std, 0, 0 FROM table1 GROUP BY Datum UNION ALL SELECT a.Datum, ' ', a.Std, m.spalte1, m.spalte2 FROM table1 a JOIN table2 m ON a.id = m.id) t2 ORDER BY Datum, Bedeutung

    Ergebnis:

    2021-03-01|     |3|..|..|
    2021-03-01|     |1|..|..|
    2021-03-01|Summe|4|0|0|
    2021-03-02|     |2|..|..|...|
    2021-03-02|Summe|2|0|0|
    

    Die horizontalen Striche bekommst Du aus einer Query natürlich nicht heraus.

    Aber - tu's nicht. Such Dir einen Reportgenerator. Zum Beispiel den - ohne Empfehlung, das war einfach mein erster Treffer beim Suchen.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Hi Rolf, hi Andreas,

      danke für Eure Antworten und Anregungen.

      Ich dachte, das gibge einfacher. Denn wenn ich bedenke, dass auf mich noch mehr zukommt als nur die Teilsummen, bin ich dann doch ziemlich sicher, dass ich das eh alles nicht in einer Query "erschlagen kann".

      Insbesondere werden auch noch mehr Tabellen herein spielen, als nur die eingangs erwähnten.

      Ob ein Reportgenerator für mich richtig wäre, kann ich grad gar nicht beurteilen, da ich diese Teile nicht kenne.

      Daher versuche ich mal zu beschreiben, worauf meine Aufgabe hinausläuft:

      Ich habe 1 Tabelle mit Vorgängen, in denen die Grunddaten dieser Vorgänge enthalten sind. Dann habe ich 2 Tabellen mit (u.a.) Arbeitszeiten (Std.) und Datum, bezogen auf diese Vorgänge. 1 Tabelle mit Mitarbeitern, bezogen auf die beiden vorangegangenen Tabellen. Daraus möchte ich dann quasi die täglichen Arbeitszeiten je Mitarbeiter ermitteln. Dann habe ich aber noch (wenisgstens) eine Tabelle mit Urlaubstagen, Krankheitstagen und Feiertagen, die je Mitarbeiter entsprechend mit 8 Std, gerechnet wird, falls der Tag kein Sa, So oder Feiertag war. Die an den Tagen geleistete Arbeit wird natürlich noch in Normalstd. und Überstunden gem. einer Liste unterteilt. Am Schluss möchte ich je Mitarbeiter einen Monatsbericht erstellen und einen Gesamtmonatsbericht aller Mitarbeiter mit den jeweiligen monatl. Gesamtstunden. Das ist der Hintergrund der Aktion und ich überlege gerade, wie ich das ganze angehe. Im Hintergrund behalten muss ich ja auch, dass ich nicht zu viele Operationen auf einen einzigen Request ablege und mir die Scriptlaufzeit ausgeht oder die Geduld des Scriptausführenden übersteigt.

      Ich denke mal, dass ich mit dieser individuellen Aufgabenstellung auch einen Scriptgenerator überfordere und außerdem macht mit das ja auch Spaß, das selber auf die Beine zu stellen. Trotzdem stehe ich gerade wirklich vor dem Problem, nicht genau zu wissen, ob ich einfach Schritt für Schritt vorgehe (was ja vom Aufwand und der Logik her überschaubar ist) oder ob es nicht einen Kniff gibt, mit dem ich mir die ganze Schritt für Schritt Arbeit erleichtern kann.

      Das war z.b. der Ausgangspunkt meiner Frage, ob ich die Summern schon in der Query mitberechnen kann.

      Jörg

      1. Hallo Jörg,

        ich würde definitiv die Rohdaten aus der DB holen und den Monatsbericht für einen Mitarbeiter per PHP in einem Request erzeugen. Ich glaube nicht, dass Du durch komplexe Query etwas gewinnst. Nur Kopfschmerzen, und du wirst dein sechs Monate jüngeres Ich verfluchen, wenn Du den Kram später mal modifizieren musst.

        Für den Gesamtmonatsbericht kommt's drauf an, wieviele Leute das sind. 10? 100? 1000? Bei bis zu 100 Leuten sollte sich das ein einem Request abfackeln lassen.

        Man kann da aber auch überlegen, das Script einmal als Batch laufen zu lassen und das Ergebnis als statische HTML Datei zu speichern.

        Rolf

        --
        sumpsi - posui - obstruxi
        1. Hallo Rolf,

          ich würde definitiv die Rohdaten aus der DB holen und den Monatsbericht für einen Mitarbeiter per PHP in einem Request erzeugen.

          Bedeutet aber, wenn der Benutzer nur den Monatsbericht bräuchte, müsste er dennoch erst alle Mitarbeiter durchrequesten.

          Ich glaube nicht, dass Du durch komplexe Query etwas gewinnst. Nur Kopfschmerzen, und du wirst dein sechs Monate jüngeres Ich verfluchen, wenn Du den Kram später mal modifizieren musst.

          Da hast Du sicher recht. Ich tendiere auch dazu, es in nachvollziehbare Schritte zu unterteilen.

          Für den Gesamtmonatsbericht kommt's drauf an, wieviele Leute das sind. 10? 100? 1000? Bei bis zu 100 Leuten sollte sich das ein einem Request abfackeln lassen.

          Es sind definitiv unter 20. Aber dieser Wert alleine ist/wäre auch nicht entscheidend. Es könnten ja auch sehr sehr viele Vorgänge mit kleinen Minutenwerten sein, um die es geht. (sind es aber nicht) 😉

          Man kann da aber auch überlegen, das Script einmal als Batch laufen zu lassen und das Ergebnis als statische HTML Datei zu speichern.

          Habe ich auch schon drüber nachgedacht. Auch darüber, nächtlich einen Cron drüber laufen hzu lassen, um mir die Daten für einen späteren Zeitpunkt komfortabel aufarbeiten zu lassen. Bin aber nicht sicher, dass das so schlau wäre, denn ich müsste ohnehin die aufgearbeiteten Daten, wenns drauf ankommt, mit dem Original vergleichen, da zwischen dem nächtlichen Cron und dem tatsächlichen Aufruf der aufbereiteten Daten ein Edit liegen könnte.

          Deshalb überlege ich gerade, ob es sinnvoll ist, den ersten von 2 ohnehin nötigen Requests (1="gehe in Monatsauswertung", 2="Datum bzw. Monat vorwählen") mit etwas "Aufräumarbeit" zu belegen und den 2. Request dann für den dann etwas fixeren Datenaufruf zu nutzen, der dann ggf. auch alle Mitarbeiter in einem Zug zur Monatsauswertung schafft.

          Jörg