Auswertung einer Umfrage
Alex
- datenbank
0 Vinzenz Mai0 Alex
Mahlzeit,
ich schraube gerade an einer Datenbankabfrage für eine Umfragesoftware und könnte etwas Hilfe beim Weiterentwickeln meines bisherigen Ergebnisses gebrauchen. Folgende Tabellen und Felder sind relevant:
questions:
answer_types:
answer_values:
results: (vom Benutzer ausgewählte Antworten in Multiple Choice u.ä.)
results_text: (vom Benutzer frei eingegebene Texte)
Wie man sieht, ist diese Struktur nicht komplett normalisiert -- das DB-Design ist aber vorgegeben. Ich hantiere hier übrigens mit MySQL 5.
Nun möchte ich aus Datensätzen dieser DB die Auswertung einer Umfrage erstellen. Gehen wir mal davon aus, daß es nur zwei Fragetypen gibt:
(A) Multiple Choice (Tabelle results) und
(B) Textfelder, die der Benutzer nach Belieben ausfüllen kann (Tabelle results_text).
Für A interessieren mich in der Auswertung die verfügbaren Optionen mit Text (answer_values.value) und wie häufig jede dieser Optionen insgesamt ausgewählt wurde.
Für B möchte ich einfach eine Auflistung der Texte haben (results_text.answer). Inhaltliche Doppelungen werden nicht berücksichtigt, d.h. wenn zwei Leute den gleichen Text geschrieben haben, dürfen ruhig beide Texte in der Auswertung auftauchen.
Das ist erstmal nicht so kompliziert und funktioniert im Einsatz auch schon. Allerdings werden u.A. die Antworten auf jeweils eine Frage einzeln von der DB erfragt -- nicht besonders schön, besonders bei umfangreichen Umfragen. Das muß sich doch auch in einem Rutsch erledigen lassen, dachte ich mir und widmete mich erstmal Teil A. Das sah dann so aus:
SELECT
q.qid, q.question, q.aid,
a.type,
av.avid, av.value,
COUNT(av.avid)
FROM
questions q,
answer_types a,
answer_values av,
results r
WHERE
-- nur die Fragen einer bestimmten Umfrage
q.sid = 32
-- nur die Antworttypen der vorher gefilterten Fragen
AND a.aid = q.aid
-- nur die Antwortwerte der vorher gefilterten Antworttypen
AND av.aid = a.aid
-- nur die ausgewählten Antworten (Ergebnisse) auf vorher
-- gefilterte Fragen und Antwortwerte
AND r.qid = q.qid
AND r.avid = av.avid
GROUP BY
av.avid, q.qid
Das läßt sich natürlich auch mit JOINs schreiben. Ich wollte beim Konstruieren nur erstmal den Überblick behalten, und das fiel mir leichter mit den Kreuzprodukt mehrere Tabellen, welches jeweils durch WHERE gefiltert wird ...
Beim Ergebnis gibt es allerdings ein Problem: Durch die Gruppierung gehen Antworttypen verloren, die kein einziges Mal ausgewählt wurden (wofür COUNT(av.avid) also 0 liefern würde). Krieg ich doch bloß wieder durch JOINs mit hinein?
Dann fehlt natürlich noch Teil B der Auswertung, und hier steh ich nun wirklich auf dem Schlauch. Das Endergebnis muß ja etwas Gemischtes sein, Weil sich A und B in der Art und Weise, wie sie in der DB abgelegt werden, ziemlich unterscheiden. Ich stelle mir das etwa so vor (mc = Multiple Choice, txt = freier Texteintrag):
+-----+------+---------------+------------------+------+
| qid | type | question | value | cnt |
+-----+------+---------------+------------------+------+
| 1 | mc | Was gibt's? | Nichts | 120 |
| 1 | mc | Was gibt's? | Ärger | 50 |
| 2 | txt | Und sonst so? | Muß ja. | NULL |
| 2 | txt | Und sonst so? | Gut. Und selber? | NULL |
| 2 | txt | Und sonst so? | Ooch, weiß nich. | NULL |
+-----+------+---------------+------------------+------+
Wie krieg ich meinen bisherigen Ansatz noch erweitert, um results_text in dieser Form mit ins Ergebnis einfließen zu lassen? (Oder ist es gar keine so gute Idee, diese beiden unterschiedlichen Ergebnistypen auf Teufel komm raus in dieser Form miteinander verheiraten zu wollen?)
Für jeden hilfreichen Tip dankbar,
Alex
Hallo,
Beim Ergebnis gibt es allerdings ein Problem: Durch die Gruppierung gehen Antworttypen verloren, die kein einziges Mal ausgewählt wurden (wofür COUNT(av.avid) also 0 liefern würde). Krieg ich doch bloß wieder durch JOINs mit hinein?
Deine Abfrage ist leider so kaputt, dass nur MySQL keinen Syntaxfehler meldet. (Du wählst sechs Spalten aus, die keine Aggregatsfunktion enthalten - gruppierst jedoch nur nach zwei davon).
Und ja, Du benötigst OUTER JOINS.
Abgesehen davon finde ich explizite Joinsyntax wesentlich übersichtlicher und verständlicher als alles in der WHERE-Klausel zu mixen. Ich schreib' erst mal auf explizite Join-Syntax um, um die Abfrage zu verstehen, wenn implizite Joins verwendet werden.
Um Dir besser helfen zu können, liefere doch bitte ein paar Beispieldaten, sowohl für Multiple Choice, als auch Text.
+-----+------+---------------+------------------+------+
| qid | type | question | value | cnt |
+-----+------+---------------+------------------+------+
| 1 | mc | Was gibt's? | Nichts | 120 |
| 1 | mc | Was gibt's? | Ärger | 50 |
| 2 | txt | Und sonst so? | Muß ja. | NULL |
| 2 | txt | Und sonst so? | Gut. Und selber? | NULL |
| 2 | txt | Und sonst so? | Ooch, weiß nich. | NULL |
+-----+------+---------------+------------------+------+
Wie krieg ich meinen bisherigen Ansatz noch erweitert, um results_text in dieser Form mit ins Ergebnis einfließen zu lassen?
UNION könnte Dir helfen.
(Oder ist es gar keine so gute Idee, diese beiden unterschiedlichen Ergebnistypen auf Teufel komm raus in dieser Form miteinander verheiraten zu wollen?)
Ich würde diese beiden Typen *nicht* zusammenstellen.
Freundliche Grüße
Vinzenz
Hallo,
Deine Abfrage ist leider so kaputt, dass nur MySQL keinen Syntaxfehler meldet. (Du wählst sechs Spalten aus, die keine Aggregatsfunktion enthalten - gruppierst jedoch nur nach zwei davon).
Es fällt mir schwer, dazu etwas zu sagen, da MySQL bisher das einzige RDBS ist, mit dem ich zu tun hatte. ;-)
Um Dir besser helfen zu können, liefere doch bitte ein paar Beispieldaten, sowohl für Multiple Choice, als auch Text.
Das wird sehr schnell sehr viel. Deshalb erstmal ein etwas überschaubarerer Auszug:
questions:
+-----+-----+------+----------------------------------------------------+
| sid | qid | aid | question |
+-----+-----+------+----------------------------------------------------+
| 32 | 318 | 1006 | In welcher Gruppe hast Du gearbeitet? |
| 32 | 319 | 1007 | Welche Programmiersprachen beherrschst Du? |
| 32 | 321 | 1008 | Sollten lieber JOINs benutzt werden? |
| 32 | 324 | 1008 | Kommen auch andere DBS zum Einsatz? |
| 32 | 342 | 999 | Welche anderen Programmiersprachen beherrschst Du? |
+-----+-----+------+----------------------------------------------------+
answer_types:
+------+-----+------+
| aid | sid | type |
+------+-----+------+
| 999 | 32 | T | <- Textfeld
| 1006 | 32 | MS | <- Multiple Choice mit Einfachankreuzen
| 1007 | 32 | MM | <- Multiple Choice mit Mehrfachankreuzen
| 1008 | 32 | MS |
+------+-----+------+
answer_values:
+------+------+-------------------+
| avid | aid | value |
+------+------+-------------------+
| 4040 | 1006 | Produktdesign |
| 4041 | 1006 | Schaltungstechnik |
| 4042 | 1006 | Programmierung |
| 4045 | 1007 | C/C++ |
| 4046 | 1007 | Haskell |
| 4047 | 1007 | Java |
| 4048 | 1007 | Andere ... |
| 4051 | 1008 | Ja |
| 4052 | 1008 | Nein |
+------+------+-------------------+
results:
+------+-----+-----+------+
| rid | qid | sid | avid |
+------+-----+-----+------+
| 1678 | 321 | 32 | 4051 |
| 1698 | 321 | 32 | 4051 |
| 1716 | 321 | 32 | 4051 |
| 1849 | 319 | 32 | 4045 |
| 1877 | 318 | 32 | 4041 |
| 1953 | 318 | 32 | 4042 |
| 1982 | 318 | 32 | 4041 |
| 1985 | 319 | 32 | 4045 |
| 1990 | 324 | 32 | 4051 |
| 2019 | 318 | 32 | 4042 |
| 2021 | 319 | 32 | 4046 |
| 2026 | 319 | 32 | 4048 |
| 2027 | 324 | 32 | 4052 |
| 2039 | 318 | 32 | 4040 |
| 2040 | 319 | 32 | 4045 |
| 2041 | 319 | 32 | 4046 |
| 2042 | 319 | 32 | 4047 |
| 2043 | 319 | 32 | 4048 |
| 2047 | 324 | 32 | 4052 |
+------+-----+-----+------+
results_text:
+------+-----+-----+---------+
| rid | qid | sid | answer |
+------+-----+-----+---------+
| 249 | 342 | 32 | Cobol |
| 311 | 342 | 32 | Fortran |
| 316 | 342 | 32 | Fortran |
+------+-----+-----+---------+
Wie krieg ich meinen bisherigen Ansatz noch erweitert, um results_text in dieser Form mit ins Ergebnis einfließen zu lassen?
UNION könnte Dir helfen.
Klingt nicht schlecht. Das probier ich eventuell mal aus. Je nachdem, wie Deine Antwort auf die Folgefrage ausfällt. ;-)
(Oder ist es gar keine so gute Idee, diese beiden unterschiedlichen Ergebnistypen auf Teufel komm raus in dieser Form miteinander verheiraten zu wollen?)
Ich würde diese beiden Typen *nicht* zusammenstellen.
Was wäre Dein alternativer Vorschlag? Lieber zwei getrennte Abfragen oder einfach nur die beiden Typen auf jeweils eigene Spalten im Ergebnis verteilen?
Viele Grüße
Alex