SQL Umfrage auswerten - gehts einfacher ?

HansDampf38

Lt. Junior Grade
Registriert
Jan. 2008
Beiträge
381
DB = MySQL
Sprache = PHP

Hallo,

also ich habe ne Umfrage, wo die Ergebnisse in einer MySQL-Tabelle geschrieben werden. Die Antworten sind nur "Ja" oder "Nein". Bisher sieht meine Auswertung so aus: (vereinfacht dagestellt)

Code:
erg1 = SELECT * FROM umfrage WHERE antwort1 = ja
erg2 = SELECT * FROM umfrage WHERE antwort1 = nein

erg3 = SELECT * FROM umfrage WHERE antwort2 = ja
erg4 = SELECT * FROM umfrage WHERE antwort2 = nein

... usw

echo erg1.count
echo erg2.count
echo erg3.count
echo erg4.count

... usw

Da ich aber nicht nur 2 Fragen haben, sondern doch ein paar mehr, wollte ich mal wissen, ob das ganze auch etwas kürzer geht ? ( Ich meinte keine Schleife, das würde ich dann eh machen, wenn es von SQL-Seite keine kürzere Variante gibt )

Danke

HD
 
ModellbahnerTT schrieb:
SELECT COUNT(*) FROM umfrage WHERE antwort1 = ja
liefert dir gleich die Anzahl der gefunden Werte.

Das kannst du dann in eine wiederverwendbare Methode Packen der du nur den veränderlichen Teil übergibst.

Mal als java ähnlichen pseudocode zur direkten Ausgabe:

public class Survey
{
private PreparedStatement pstmt = con.prepareStatement("SELECT COUNT(*) FROM umfrage WHERE ? = ?");


void printResult(String answer, String value)
{
pstmt.setString(1,answer);
pstmt.setString(2,value);
ResultSet result=pstmt.executeQuery():
...
// Abgekürzt: Ergebnisse in Variable "result" lesen
...
System.out.println("Auf " + answer + " haben " + result + " mit " + value + " geantwortet");
}

}

Dann erhältst du die Ausgaben z.B. mit
printResult("antwort1","ja");
printResult("antwort1","nein");
printResult("antwort2","ja");
printResult("antwort2","nein");

etc.

Das ganze geht natürlich noch Schöner, indem man es etwas auftrennt, die Ergebnisse in Prozent umrechnet, und dann ausgibt.

EDIT: Es mag sein, dass das so nicht funktioniert, dass man den Spaltennamen als Parameter angibt. Dann müsste man dort den String zusammensetzen.
 
Zuletzt bearbeitet:
Überlegt dir mal, ob es nicht schöner wäre BOOL oder BIT für die Antwort zu benutzen statt VARCHAR oder was auch immer du gerade benutzt. Dann benötigt deine Antwort nur ein denn 4+ Byte. Alternativ ENUM.
Und dem "COUNT(*)" würde ich per "COUNT(*) AS count" einen praktischeren Namen geben.
 
Zuletzt bearbeitet:
@DjNDB
Wie ich ganz oben geschrieben, nutze ich PHP, daher bringt mir den Java-Code nichts, aber trotzdem Danke für dein bemühen :)

@b03ch7
War meine erste Idee, aber dann kam leider dazu das es durch aus auch ein "vielleicht" geben könnte und daher klappt Bool nich :D

@ModellbahnerTT
Hab das nun mal getestet, aber weniger wirds trotzdem nicht, oder was ist der Unterschied, bzw. besser an count bei den 2 Varianten:

Code:
$sql = "SELECT * FROM umfrage_tb WHERE antwort1 = 'ja'";
$db_erg = mysql_query( $sql );
$count = mysql_num_rows($db_erg);

Code:
$sql = "SELECT COUNT(*) FROM umfrage_tb WHERE antwort1 = 'ja'";
$db_erg = mysql_query( $sql );
$count = mysql_result($db_erg,0);

Brauch in beiden Fällen die selben Anzahl von Befehlen.

Gruß

HD
 
Es gibt sehr wohl einen Unterschied zwischen

SELECT * FROM ... WHERE bedingung
mysql_num_rows

und

SELECT COUNT(*) FROM ... WHERE bedingung
mysql_fetch_row



Ersteres liefert alle betroffenen Datensätze (Speicherbedarf für n>=0 Zeilen)
Letzteres liefert GENAU eine Zeile.


Jetzt die rhetorische Frage: was ist jetzt wohl effektiver?
 
ich würde sagen die count variante, weil wie gesagt auch nur eine zeile ausgelesen wird.
 
Sein Hauptanliegen ist aber doch, die 4 SELECTs (bzw. hat er wohl noch mehr) durch möglichst nur 1 SELECT ersetzen zu können, und nicht die einzelnen SELECTs beschleunigen (wobei das zusätzlich natürlich dann auch noch sinnvoll ist).

Ich kenn mich damit nicht wirklich aus, aber sollte das nicht irgendwie mit JOIN möglich sein?
 
http://sql.1keydata.com/de/sql-group-by.php

Das würde natürlich nur gehen, wenn du in der Tabelle "Umfrage" nicht für jeder Antwortmöglichkeit eine Spalte nutzt. Aus der Ferne beurteilt eh nicht sonderlich schön. Du brauchst eine Spalte "Antwortfrage" - da kommen die Werte Frage1, Frage2, etc... drin vor - und eine Spalte "Antwort" - für die jeweiligen Antworten.

Code:
SELECT
   antwortfrage, count(antwort)
FROM
   umfrage
GROUP BY
   antwortfrage

Über das Ergebnis der Umfrage könntest du mit einer Schleife drüber iterieren und bekommst je "Antwortmöglichkeit" deine Anzahl an Antworten.
 
SELECT COUNT(*) / SELECT * sollte man aber tunlichst vermeiden... bei größeren Tabellen wird das extrem langsam...

Dem COUNT() immer eine Spalte geben die er benutzen soll...
 
Mojo1987 schrieb:
SELECT COUNT(*) / SELECT * sollte man aber tunlichst vermeiden... bei größeren Tabellen wird das extrem langsam...

Dem COUNT() immer eine Spalte geben die er benutzen soll...

SELECT COUNT(*) FROM table

... (wohlgemerkt ohne WHERE) ist NICHT langsam, weil der SQL-Optimierer dann die Tabellenstatistik zu Rate zieht (Wieviele Zeilen hat die Tabelle? 20.237.182 - ah ja danke - Rückgabe)

Wenn Abfragen langsam sind, sind vermutlich die Indexe falsch oder gar nicht gesetzt.

Dazu EXPLAIN SELECT zu Rate ziehen.

Wenn man natürlich Abfragen schreibt, die einen FULL-TABLE-SCAN implizieren, ist man selbst Schuld.
 
ich gehe bei fragen die nicht den index betreffen eigentlich davon aus, dass diese "schlau" gewählt ist, bzw überhaupt ein index gesetzt ist.
 
Erstmal Danke für die Antworten.

Und es ist so, wir Mr. Snoot gesagt hat, es geht mir nich um schneller oder effektiver. Wir reden hier nicht von einer Umfrage von Microsoft, wo Hunderttausende abstimmen ;), es werden vermutlich höchsten ein paar Hundert, wenn überhaupt.

Ich dachte zuerst ich bekomme bei SELECT COUNT gleich die Anzahl zurück ohne sie noch mal über fetch auslesen zumüssen.

Hier mal ein Datensatz aufgeschlüsselt

id (PK)
ip
antwort1
antwort2
antwort3
antwort4
...

Hier mal der Code dazu:

Code:
for($i = 1; $i >= 5; $i++)
{
$query1 = "SELECT * FROM umfrage_tb WHERE antwort".$i." = 'ja'";
$query2 = "SELECT * FROM umfrage_tb WHERE antwort".$i." = 'Nein'";
$query3 = "SELECT * FROM umfrage_tb WHERE antwort".$i." = 'Vielleicht'";
$query4 = "SELECT * FROM umfrage_tb WHERE antwort".$i." = ''";

	for($y = 1; $Y >= 4; $y++)
	{
		$dump.$y = mysql_query($query.$y);
		$count.$y = mysql_num_rows($dump.$y); 
		$antwort.$y = round(($count.$y / 5 * 100),2); 
	}
}

wobei ich das mit dem .$y jetzt nicht ausprobiert habe, sonst müsste ich da noch ne Zwischenvariable einsetzen.

Habe zwar gerade das Gefühl da fehlt was, komm aber nich drauf. :freak:

Gruß

HD
 
Mojo1987 schrieb:
SELECT COUNT(*) / SELECT * sollte man aber tunlichst vermeiden... bei größeren Tabellen wird das extrem langsam...

Dem COUNT() immer eine Spalte geben die er benutzen soll...
Mit einem COUNT(*) sagt man, dass einen die Anzahl der Datensätze interessieren, bei einem COUNT(spalte) möchte man alle Datensätze bei denen spalte nicht NULL ist. Das erste ist definitiv schneller ;) Da es wie für MyIsam sich die Anzahl merkt oder bei anderen Engines einfach nur schnell im Index zählen muss, müsste es noch auf null prüfen ist es natürlich ein kleinwenig langsamer.
Und Select * ist auch nicht langsam, das ist ein Mythos der nur bei ganz bestimmten Konstellationen auftritt: Wenn Text-Spalten geladen werden, die nicht benötigt werden und eine tempöräre Tabelle erstellt werden muss, dann landet diese auf der Festplatte und nicht im Ram.
Also eigentlich stimmt keine deiner Aussagen.
 
@DjNDB
War nur ein Syntaxfehler, der mir immer wieder mal passiert :heilig:

Und sonst ? Wie sieht der Rest des Code aus ? Verbesserungsvorschläge ?

Gruß

HD
 
wenn man ganz penibel ist und das ganze in eine klasse verpackt sollten tabelle und feldnamen in konstanten bzw getter methoden
 
HansDampf38 schrieb:
@DjNDB
War nur ein Syntaxfehler, der mir immer wieder mal passiert :heilig:

Nur mal der Vollständigkeit halber:

for($i = 1; $i >= 5; $i++)
Ist kein syntaktischer Fehler (die Syntax ist nämlich korrekt), sondern ein semantischer Fehler (der Code tut nicht das, was er soll).

ice-breaker schrieb:
Und Select * ist auch nicht langsam, das ist ein Mythos der nur bei ganz bestimmten Konstellationen auftritt

Ein weiteres Szenario wäre eine Tabelle mit vielen Zeilen und Spalten, in der man einen FULL-TABLE-SCAN macht, der sogar jede Spalte zurückliefert (weil SELECT * FROM ...), obwohl nur wenige gebraucht werden.
Grundsätzlich SOLLTE man die Spalten explizit benennen, damit nicht viele neue Felder zu einer Laufzeitverzögerung bei komplexeren Abfragen führt. Eine gute Projektion ist daher sehr wichtig.
 
Zuletzt bearbeitet:
Es werden sowieso meistens alle Spalten gelesen (da sie zusammen als Block gespeichert sind) und dann einfach nur diejenigen entfernt, die nicht benötigt werden ;)
Sollten alle Daten einer Zeile in einem Block sein, ist es egal ob Select * oder nicht, interessant wird es erst bei z.B. varchar- oder text-columns bei denen die Daten möglicherweise an einer anderen Stelle in der Datei gespeichert sind, dann würden nämlich mind. 2 Random-IO-Zugriffe nötig sein:
1. Den Block mit der gesuchten Zeile finden
2. Die ausgelagerten Daten finden und laden
Und wer einen Full-Table-Scan macht muss sich sowieso nicht über Performance wundern.
 
Zurück
Oben