Michael: zusammenaddiert innerhalb einer SELECT Abfrage

Hallo, nachdem ich ein fleißiger Leser bin und mir sehr sehr viel hier herausgelesen habe, stelle ich doch mal eine Frage.

Ich erstelle ein Script mit dem man mehrere Abstimmungen ausführen kann. Jetzt habe ich ein SQL Problem, das mich fuxt.

Mit der folgenden SQL Abfrage bekomme ich meinen Datensatz für die jeweilige Abstimmung

SELECT a.id, a.questions_de AS answer,a.total FROM poll_questions a WHERE a.id_poll=:id

unter total, wird bei jeder Stimmabgabe für den betreffenden Satz die Stimme addiert.

Jetzt möchte ich gerne bei der Ausgabe, ein Feld haben, in der alle Stimmen zusammenaddiert sind (alle total Felder).

Mein Versuch mit SUM ist kläglich gescheitert.

SELECT SUM(a.total) AS total_vote, a.id, a.questions_de AS answer,a.total FROM poll_questions a WHERE a.id_poll=:id

Ich habe zwar das Ergebnis bei total_vote, doch es wird mir nur noch ein Datensatz ausgegeben.

Michael

  1. Naja...

    SELECT SUM ... WHERE a.id_poll=:id
    

    doch es wird mir nur noch ein Datensatz ausgegeben.

    Du hast es doch genau so bestellt - oder? Die Summe des Alters des dritten Kindes von links ist das Alter des dritten Kindes von links und nicht die Summe des Alters aller Kinder.

    1. Nein, hier frage ich alle Antworten ab die für die Abstimmung möglich sind

      a.id_poll=:id
      
      id_poll ! questions_de 	! total
      1		! Frage 1		!	10
      1		! Frage 2		!	20
      1		! Frage 3		!	30
      1		! Frage 4		!	10
      

      und ich will alle Zeilen mit und ein Ergebnis mit allen Feldern aus Total.

      Michael

      1. und ich will alle Zeilen mit und ein Ergebnis mit allen Feldern aus Total.

        So wie ich Dein Wollen verstehe brauchst Du entweder mehrere (genauer: zwei) Abfragen - oder Du summierst in der die Datenbank abfragenden Anwendung(¹), in der Du ja sowieso über alle Zeilen iterierst. Die Summenbildung ist mutmaßlich das mit großem Abstand Schnellste von allem, was Du da machst. (Was Performance-Fragen angeht ist mein Nickname „Programm“.)

        ¹) Scheint PHP oder Python zu sein. Also geht das.

      2. Moin,

        und ich will alle Zeilen mit und ein Ergebnis mit allen Feldern aus Total.

        Evtl. suchst du WINDOW-Funktionen, damit lässt sich z.B. zusätzlich zu den eigentlichen Daten eine Summe über eine Teilmenge ermitteln.

        Wenn das nicht hilft, wäre es sinnvoll wenn du mal Tabellendefinition und ein paar Testdaten (CREATE TABLE- und INSERT-Querys in Textform) sowie das gewünschte Ergebnis posten würdest, damit lässt sich das Problem dann leichter nachstellen.

        Gruß
        Tobias

        1. Evtl. suchst du WINDOW-Funktionen, damit lässt sich z.B. zusätzlich zu den eigentlichen Daten eine Summe über eine Teilmenge ermitteln.

          Hm. Kann man machen, verursacht aber bei einer hohen Anzahl von Treffern eine übergroße Menge zu transportierender und auszuwertender Daten. Die zusätzliche Spalte mit identischem Wert in jeder Zeile verlangsamt also den Datentransport und übrigens sodann auch die Verwertung. (Das muss ja alles „für nichts“ eingepackt, transportiert und sodann zerlegt werden.)

          Was dann dazu führt, dass die Gesamtzeit der komplexen Abfrage die der für zwei Abfragen oder der Summierung in der Anwendung klar übersteigt.

  2. Hallo Michael,

    Mein Versuch mit SUM ist kläglich gescheitert.

    SELECT SUM(a.total) AS total_vote, a.id, a.questions_de AS answer,a.total
    FROM poll_questions a
    WHERE a.id_poll=:id
    

    Die ID musst Du nicht im SELECT aufführen, weil Du sie eh schon kennst.

    SUM() ist eine Aggregatfunktion und MYSQL tut, was es soll: es aggregiert und liefert ohne GROUP BY nur eine Zeile zurück. Und damit gelangen wir zu meinem Lieblings-Rant:

    Werden aggregierte Spalten verwendet, muss jede nicht aggregierte Spalte eine Konstante sein oder in einer GROUP BY Klausel angegeben werden.

    Ich hasse MYSQL, weil es diesen Verstoß gegen die SQL Regeln zulässt.

    Und ich predige es immer wieder: Diese Mischung ist toxisch, weil der Wert der ungruppierten Spalten undefiniert ist (heißt: der Server kann sich die Row aussuchen, deren Wert er verwendet.

    Bei der ID ist es egal. Die ist eh für alle Rows gleich. Aber welchen Wert soll er bei questions_de oder total auswählen?

    GROUP BY hilft Dir hier aber nicht, weil du bestenfalls nach der id gruppieren könntest.

    Deine SQL Abfrage ist logisch unsinnig. Eine Mischung aus aggregierten und nicht aggregierten Daten in einer Query passt nicht zusammen - das sind zwei unterschiedliche Sichten auf die Daten und eine Query sollte nur eine Sicht liefern. Denn andernfalls musst Du das Query-Ergebnis nachher im Programm auseinandernehmen und die Dinge, die zu unterschiedlichen Sichten gehören, wieder trennen.

    Heißt hier: Du musst die Summe wieder von den Einzeldaten trennen.

    Was Du keinesfalls willst, ist, die Summe für jede Einzelzeile zu berechnen. Auch dann müsstest Du die Daten trennen (du müsstest Dir die Summe in der Zeilenschleife merken und sie nach der Schleife verwenden). Diese Query käme deinem Versuch wohl am nächsten, aber verwende sie bloß nicht:

    SELECT a.questions_de AS answer
         , a.total
         , (SELECT SUM(b.total) 
            FROM poll_questions b WHERE b.id = :id) as total_vote
    FROM   poll_questions a
    WHERE  a.id_poll=:id
    

    Brrr 🤮 - der SQL Server müsste für jede Ergebniszeile neu summieren.

    Was man tun könnte, wäre, die Summe an die Einzelzeilen als separate Zeile anzuhängen, mit dem UNION ALL Operator. Wegen der schon diskutierten Rangvermischung rate ich dringend davon ab.

    SELECT 0 as Rang, a.questions_de AS answer, a.total
    FROM   poll_questions a
    WHERE  a.id_poll=:id
    UNION ALL
    SELECT 1 as Rang, NULL, SUM(a.total)
    FROM   poll_questions a
    WHERE  a.id_poll=:id
    

    Die Detailzeilen bekommen Rang 0, die Summenzeile bekommt Rang 1. In der Summenzeile wird die ID als Konstante eingesteuert und die Antwort ist irrelevant, daher die NULL. Einzelzeilen und Summenzeile werden per UNION ALL zusammengefügt. UNION deshalb mit ALL, weil SQL andernfalls versucht, doppelte Zeilen zu finden und zu eliminieren. Die :id steht als Konstante in der SELECT-Liste des zweiten Select.

    Eine solche Query hat in genau einem Kontext Sinn: Wenn Du die im phpmyadmin eingibst, um schnell mal eine Aufstellung mit Details und Summe zu bekommen, ohne einen Reportgenerator anzuwerfen. In einem Programm hat eine solche Query nichts zu suchen.

    Fazit: Bilde die Summe im PHP (oder im Reportgenerator).

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Danke für die Antworten. Ich wollte es einfach und praktisch machen. Doch einfach ist manchmal nicht die richtige Antwort. Ich berechne die Summe nach der Abfrage der Datenbank mittels PHP.

      Jedenfalls super für die ganzen Hinweise.

      Michael

      1. Erst einmal das „Danke für die Rückmeldung!“

        Doch einfach ist manchmal nicht die richtige Antwort. Ich berechne die Summe nach der Abfrage der Datenbank mittels PHP.

        Nanu? Genau das ist doch offensichtlich das Einfachste.