Rolf B: zusammenaddiert innerhalb einer SELECT Abfrage

Beitrag lesen

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