Ankündigung

Einklappen
Keine Ankündigung bisher.

Werte kumulieren und aufaddieren

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Werte kumulieren und aufaddieren

    Hallo liebe PHP-Gemeinde,

    ich habe mal wieder ein Problem bei dem ich nicht weiter komme und eure Hilfe benötige

    Ich würde gern Werte einer Datenbankspalte eines bestimmten Datums summieren und kumulieren. Mein erster Ansatz funktioniert auch, allerdings nur über die ganze Tabelle hinweg.

    Code:
    SELECT datumzeit, wert,
      (SELECT SUM(wert)
      FROM werteges
      WHERE datumzeit <= b.datumzeit
      ) AS gesamt
    FROM werteges AS b
    WHERE datumzeit BETWEEN '2020-05-01 00:00:00' AND '2020-05-08 23:59:00'
    ORDER BY datumzeit
    Das Ergebnis ist, dass ich hier nicht die Werte zw. dem 01.05.20 und 08.05.20 angezeigt bekomme, sondern alle Werte der Spalte "wert".
    Nochmal zum Verständnis, es soll so aussehen:

    datumzeit | wert | gesamt
    01.05.20 | 2 | 2
    02.05.20 | 1 | 3
    03.05.20 | 5 | 8
    04.05.20 | 2 | 10
    05.05.20 | 3 | 13
    06.05.20 | 8 | 21
    07.05.20 | 11 | 32
    08.05.20 | 1 | 33

    und so sieht es aus:

    datumzeit | wert | gesamt
    01.05.20 | 2 | 5528 = Summe aller Werte aus der Spalte "wert"
    02.05.20 | 1 | 5529
    03.05.20 | 5 | 5534
    04.05.20 | 2 | 5536
    05.05.20 | 3 | 5539
    06.05.20 | 8 | 5547
    07.05.20 | 11 | 5558
    08.05.20 | 1 | 5559

    Meine Frage: wie bekomme ich es hin, dass ich wirklich nur die Werte des ausgewählten Bereiches angezeigt bekomme?
    Mir ist schon klar, dass bei WHERE datumzeit <= b.datumzeit die ganze Tabelle abgefragt wird, aber ich habe keine Ahnung wie ich hier meinen gewünschten Bereich einfügen kann

    Kann mir vl jemand einen Tipp geben?

    VG
    Sascha


  • #2
    Dafür verwendet man Window-Funktionen, die Dein MySQL möglicherweise nicht kennt.

    Code:
    test=*# create table demo (id serial primary key, val int);
    CREATE TABLE
    test=*# insert into demo(val) select random()*100 from generate_series(1,10);
    INSERT 0 10
    test=*# select * from demo;
     id | val
    ----+-----
      1 |  69
      2 |  41
      3 |  28
      4 |  28
      5 |  61
      6 |  31
      7 |  20
      8 |  65
      9 |  83
     10 |  21
    (10 rows)
    
    test=*# select *, sum(val) over (order by id) from demo;
     id | val | sum
    ----+-----+-----
      1 |  69 |  69
      2 |  41 | 110
      3 |  28 | 138
      4 |  28 | 166
      5 |  61 | 227
      6 |  31 | 258
      7 |  20 | 278
      8 |  65 | 343
      9 |  83 | 426
     10 |  21 | 447
    (10 rows)
    
    test=*#
    PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

    Kommentar


    • #3
      Ja ja, akretschmer wieder mit seinem Werbeprogramm. Meistens hat er ja Recht. Hier hat mySQL an der Ecke nach Jahren aber mal endlich etwas nachgezogen mit V8. Was nicht heißen soll, dass ich den Einsatz von mySQL empfehle, das Gegenteil wäre der Fall. Aber man soll ja fair bleiben.

      Hast Du die neue mySQL V8 im Einsatz oder irgendeine PostgreSQL der letzten 15 oder so Jahre? Dann:

      Was Du suchst ist kein Problem der Datumseinschränkung bzw. Du hast dieses Problem nur, weil Du mit einem Workaround hantierst.
      Was Du als Ergebnis haben möchtest nennt sich: Running Total
      Was Du dafür anwenden musst/solltest: Window Functions

      Die Lösung wurde schon skizziert, unter den Stichworten Running Total und Window Functions findest Du massig Beispiel, sicher auch mit Datum.

      Kommentar


      • #4
        Code:
        SELECT t1.datumzeit, t1.wert, SUM(t2.wert) AS gesamt
        FROM werteges t1
        INNER JOIN (
            SELECT datumzeit, wert
            FROM werteges
            WHERE datumzeit BETWEEN '2020-05-01 00:00:00' AND '2020-05-08 23:59:00'
        ) t2 ON (t2.datumzeit <= t1.datumzeit)
        GROUP BY t1.datumzeit, t1.wert
        HAVING gesamt IS NOT NULL
        ORDER BY t1.datumzeit

        Kommentar


        • #5
          hellbringer
          welch ein umständliches Gemurkse!
          Code:
          CREATE TABLE werte(id int, wert int);
          INSERT INTO werte(id, wert)VALUES
          (1, 10),
          (2, 20),
          (3, 30),
          (4, 10),
          (5, 20),
          (6, 30),
          (7, 10),
          (8, 20),
          (9, 30),
          (10, 10);
          query

          Code:
          select id, wert, (@a := @a + wert) as summe
          from werte, (SELECT @a := 0) tmp
          where id between 2 and 4

          Kommentar


          • #6
            Zitat von zorro001 Beitrag anzeigen
            welch ein umständliches Gemurkse!
            Die Umständlichkeit von verschiedenen Workarounds "abzuwägen", ist natürlich auch möglich.
            Dabei ein abstraktes, vereinfachtes Beispiel zu liefern und eine konkrete Lösung zu bemeckern, ist allerdings nicht so die feine Art.

            Hellbringer liefert als Einziger eine passende Lösung!

            Und zu den mySQL Variablen, die sind wirklich ein witzige Sache. Man kann eine Menge krankes Zeug damit machen. Habe ich auch schon als Ersatz empfohlen. Sehr gut geeignet für Workarounds!
            Ob man auf dem Weg garantiert seine SQL Kompatibilität verliert
            oder ob diese Verfahren wirklich robust sind
            oder wartungsfreundlich
            ..
            kann ich nicht alles beantworten.

            Kommentar


            • #7
              Zitat von Perry Staltic Beitrag anzeigen
              Dabei ein abstraktes, vereinfachtes Beispiel zu liefern....
              Das ist ein Programmierforum und kein kostenloser Programmierservice. Diese 'abstrakte' Lösung anzupassen überlasse ich dem Ersteller des Threads

              Zitat von Perry Staltic Beitrag anzeigen
              und eine konkrete Lösung zu bemeckern, ist allerdings nicht so die feine Art.
              Hellbringer liefert als Einziger eine passende Lösung!
              Hellbringer motzt über jede Codezeile die ihm nicht passt, bemängelt nummerierte Variablen, und liefert so etwas ab? Ich beobachte dieses Forum schon viele Jahre und habe von einigen Forumteilnehmern sehr viele Tricks mitnehmen können. Leider verschwinden immer mehr aktive Teilnehmer und leider kommen viele neue Teilnehmer nicht mehr wieder, bestimmt weil es hier so "freundlich" zugeht.


              Zitat von Perry Staltic Beitrag anzeigen
              Und zu den mySQL Variablen, die sind wirklich ein witzige Sache. Man kann eine Menge krankes Zeug damit machen. Habe ich auch schon als Ersatz empfohlen. Sehr gut geeignet für Workarounds!
              Ob man auf dem Weg garantiert seine SQL Kompatibilität verliert
              oder ob diese Verfahren wirklich robust sind
              oder wartungsfreundlich
              ..
              kann ich nicht alles beantworten.

              Ich schon, diese Verfahren sind robust. Ich zeigte das deswegen, weil nicht jeder weiß, wie man Variablen innerhalb einer! Query definiert

              SQL-Kompatibilität - pfeif drauf - man soll das nutzen was die Datenbank bietet. Der nahtlose Wechsel von Daba zu Daba ist und bleibt ein unerfüllter Traum.

              Grundlage Daten aus #5

              Postgres:
              Code:
              select *, sum(wert) over (order by id) from werte
              where id between 4 and 6;
              SQLite
              Code:
              SELECT id, wert, SUM(wert)
              OVER (ROWS UNBOUNDED PRECEDING) as sum
              FROM werte where id between 4 and 6
              MySQL:

              Code:
              select id, wert, (@a := @a + wert) as summe
              from werte, (SELECT @a := 0) tmp
              where id between 4 and 6
              Hellbringer adaptiert:
              Code:
              SELECT t1.id, t1.wert, SUM(t2.wert) AS summe
              FROM werte t1
              INNER JOIN (
                  SELECT id, wert
                  FROM werte
                  WHERE id BETWEEN 4 AND 6
              ) t2 ON (t2.id <= t1.id)
              GROUP BY t1.id, t1.wert
              HAVING summe IS NOT NULL
              ORDER BY t1.id
              Die Ergebnisse der ersten 3 Querys sind gleich....

              Kommentar


              • #8
                OT
                Ja, kein Programmierservice, klar. Gern gehörter Spruch hier, darum ging es mir aber nicht.
                Es war eher: Wenn schon meckern und vergleichen dann richtig, aber das hast Du ja nun nachgeliefert, gut!

                Motzen:
                Auf die Standards zu pochen, ist nicht motzen. Gemurkse dagegen ist ein unpassender Begriff für etwas, das ich schlicht eine Standardlösung nennen würde, die für jedes Datenbanksystem funktioniert, Basics also, kein Gemurkse. Die Prinzipien der Mengen basierten Datenverarbeitung bringen das mit sich. Jeder mit etwas SQL Erfahrung versteht das Konstrukt bzw. würde dort landen, wenn er eine solche Sache erledigen muss. Vor vielen (vielen) Jahren ging es überhaupt nicht anders.

                Nur mal zum Spaß (Geschichte):
                Nach meiner Kenntnis gibt es die Window Functions -wie in der Lösung für Postgres oben-, die für solche Problemstellungen richtungsweisend sind, bei Oracle Database (Version 8i -nicht zu verwechseln mit mySQL V seit 1999(!) ungefähr, also ca 20 Jahre. Dann kam Postgres* und lange nichts. SQLite hat es vor ca. 1 Jahr(?) umgesetzt- bei denen steht glaub ich sogar in der Doku, dass sie einfach die Postgres Funktion umgesetzt haben. Alle anderen mussten jahrelang „murksen“, sprich Standard SQL einsetzen. Und das ist auch gar nicht schlimm, so funktioniert eben SQL. Und da wären wir wieder bei mySQL- vielleicht waren die mit V8 und Window Functions auch kurz vor SQLite, weiß nicht mehr genau. mySQL ist mit seiner Entwicklung seit Oracle leider gewissen Zwängen unterworfen.

                Ich habe nichts gegen „Tricks“ und ich habe nichts gegen die Variablen von mySQL, wie gesagt, hab ich selbst schon oft vorgeschlagen, wenn es sich anbot. Aber es ist und bleibt eben eine Insellösung, solange niemand anders diese nette Idee aufnimmt. Da ich mySQL niemals ernsthaft verwenden würde, sind alle diese Fragen meinerseits letztlich reine Theorie, egal ob es um Robustheit oder sonstwas geht.

                Laber Rhabarber
                Am Ende geht es in meinem Beitrag hauptsächlich um den Tonfall. Man muss sich in einem solchen Forum nicht gegenseitig runtermachen, es bringt keinen Mehrwert. Mglw. hab ich das auch Hellbringer schon mal geschrieben, aber das ist sicher länger her, das Internet vergisst ja leider nichts.
                (und ja, Kein-Service hin oder her, die Hilfesuchenden finden natürlich eine Antwort mit funktionierender Lösung am besten).

                * Ehrlich gesagt, keine Ahnung wie es bei DB2 oder Informix usw. war, ich schätze, nichts war da. Irgendwann hat auch MS nachgeholt, usw. usw.

                /OT

                Ein Vergleich von „Lines of (SQL) Code“ und eine „offensichtliche“ Eleganz, weil kurz, knackig, übersichtlich ist eine Sache. Eine andere ist dann ein Ausführungsplan und die Skalierung eines SQL Statements. Ich will nicht behaupten ein Aggregat SQL könnte besonders flott sein, wenn es um große Datenmengen geht, aber ein kurzes SQL Statement bietet dagegen auch erst mal nicht mehr als seine eigene Übersichtlichkeit, immerhin.
                Window Functions bieten per se dem Optimizer die Gelegenheit, Aggregate und Mehrfach-(/Full) Scans zu vermeiden und liefern damit neben dem eleganteren Code den eigentlichen Vorteil- sofern der Optimizer auch wirklich weiß, was in dem Fall zu tun ist bzw. wo er sparen kann. Davon würde ich aber pauschal mal schwer ausgehen. Denn das ist ja der Witz an der Sache.

                Dein Beispiel für mySQL-auch wenn es hier gewissermaßen firmenintern universell ist für viele mySQL Versionen- trägt den neuen Fähigkeiten der Version 8 nicht Rechnung. Für Einsteiger und für die Zukunft also auch nicht unbedingt der beste Tipp. (Stichwort "gemurkse")

                Kommentar


                • #9
                  Perry Staltic

                  es ist löblich, dass du Hellbringer in Schutz nimmst. Hellbringers Tonfall ist so oft daneben, da muss er das aushalten.

                  Deine Aussage "Hellbringer liefert als Einziger eine passende Lösung!" ist
                  Code:
                  !== true
                  Ich bleibe dabei, das was hellbringer abgeliefert hat, ist einfach nur Gemurkse.
                  Standard SQL nutzt nichts, wenn Murks hinten raus kommt.

                  Der TE möchte einen Datumsbereich auswählen und dessen Werte aufsummieren.

                  Schaue die Abfrage mal genau an, das muss man sehen ohne in die Tasten zu hauen:

                  Code:
                  SELECT t1.datumzeit, t1.wert, SUM(t2.wert) AS gesamt
                  FROM werteges t1
                  INNER JOIN (
                      SELECT datumzeit, wert
                      FROM werteges
                      WHERE datumzeit BETWEEN '2020-05-01 00:00:00' AND '2020-05-08 23:59:00'
                  ) t2 ON (t2.datumzeit <= t1.datumzeit)
                  GROUP BY t1.datumzeit, t1.wert
                  HAVING gesamt IS NOT NULL
                  ORDER BY t1.datumzeit
                  Diese Query funktioniert nur, wenn keine Datensätze über den 8.5.2020 hinaus vorhanden sind. !!!!

                  Sind Daten über den 8.5.2020 hinaus vorhanden, werden diese angezeigt mit dem letztem Summenwert vom 8.5.2020.

                  Das ist MURKS weil einfach nur dahingeschmissen, ohne es zu prüfen.

                  Das hatte ich bereits in #5 und nochmal in #7 im letzten Satz angedeutet.
                  Wie oft soll ich es denn noch schreiben, bis Du oder andere das verstehen.

                  Ich würde es in V8 wie folgt erledigen und in 5.7 ein AND id <= .... hinzufügen

                  Code:
                  SELECT id wert,
                  SUM(wert)
                  OVER(ORDER BY id) AS summe
                  FROM werte
                  where id between 4 and 6
                  Also wie akretschmer in #2

                  Die Kritikfähigkeit einiger "Spezialisten" im Forum ist schlecht.

                  Wie ist es sonst zu erklären, dass hellbringer seine fachlich daneben liegende Antwort nicht korrigiert?

                  Kommentar


                  • #10
                    Zitat von zorro001 Beitrag anzeigen

                    MySQL:

                    Code:
                    select id, wert, (@a := @a + wert) as summe
                    from werte, (SELECT @a := 0) tmp
                    where id between 4 and 6
                    So funktioniert es.
                    Vielen Dank!

                    Kommentar

                    Lädt...
                    X