Problem: Array enthält nicht alle Werte

  • Hallo allerseits,

    ich habe mal wieder ein ziemlich leidiges PHP-Problem...

    Und zwar geht es grob gesagt darum, Daten aus zwei verschiedenen MySQL-Tabellen auszulesen, diese in Beziehung zueinander zu setzen und als eine Tabelle in PHP/HTML auszugeben.

    Zum einen habe ich da eine Tabelle in der alle Nutzer meines Webprojektes verzeichnet sind: users.

    Diese Nutzer durchlaufen einen Test/Fragebogen und die Antworten (30 Stück in diesem Fall) werden jeweils in der Tabelle antworten gespeichert, und zwar einschließlich der User-ID aus users.

    Die Ausgabe soll jetzt folgendermaßen geschehen (3 Spalten):

    -> Liste alle IDs (Spalte 1) und dazugehörige User (Spalte 2)

    -> WENN sich eine ID aus users auch im Feld ID der Tabelle antworten findet
    -> zeige eine Link "Ergebnis ansehen" für diesen User (Spalte 3)

    -> ANSONSTEN zeige "-" (Spalte 3)

    Mein PHP-Code dazu sieht momentan so aus

    Das Problem ist jetzt folgendes: Es gibt momentan 3 verzeichnete User, von denen einer den Test bereits absolviert hat, aber auch an dieser Stelle wird ein "-" ausgegeben.
    Das liegt daran, dass das Array $antworten die entspechende User-ID nicht enthält, obwohl Sie in der Tabelle antworten entahlten ist.
    Genauer gesagt enthält $antworten nur eine einizige User-ID.
    Ich kann mir aber nicht erklären warum.

    Danke schonmal für eure Hilfe!

  • Das liegt daran, dass das Array $antworten die entspechende User-ID nicht enthält, obwohl Sie in der Tabelle antworten entahlten ist.

    $antworten enthält ein einziges Tupel des Resultsets der zweiten Abfrage, nicht das gesamte Resultset.

    Ich würde das auf Datenbankebene lösen, etwa mit folgender Abfrage, wenn ein Benutzer höchstens ein Mal in der Tabelle antworten vorkommt:

    Code
    select u.id, u.name, a.id from user u natural left join antworten a;


    Dann ist a.id NULL, wenn der User in der Tabelle antworten nicht vorkommt.

    Oder, wenn antworten Paare aus User-ID und Antwort enthält, dann vielleicht so:

    Code
    select u.id, u.name, count(a.id) as anzahl from user u natural left join antworten a group by u.id, u.name;

    Dann solltest du in der Spalte anzahl des Resultsets die Anzahl der bereits von dem User beantworteten Fragen bekommen.

  • Allerwichtigester tipp zu PHP + Datenbank: unbedingt möglichst viel in der Datenbank berechnen, möglichst wenige Daten zu PHP schicken.


    In diesem Fall:

    SELECT users.ID, COUNT(antworten.ID)
    FROM users LEFT JOIN antworten ON ID
    GROUP BY users.ID

    das gibt die nur die Liste der IDs und die Anzahl der dazu gespeicherten Antworten. Kannst Du in einer Schleife durchlaufen und ausgeben.
    Brauchst keine (potentiell riesigen) Arrays in PHP.


    p.s.
    Und später trennst Du dann Logik und Darstellung, z.B. mit Smarty Templates oder MVC.

    Brigitte Jellinek - http://multimediatechnology.at/web-communities/
    Ich unterrichte in einem Medieninformatik-Studium (BSc, MSc) mit Schwerpunkt Web Development
    Meine Themen: Ruby on Rails, Javascript, SCRUM, git, Test Driven Development,...

  • Ich würde das auf Datenbankebene lösen, etwa mit folgender Abfrage, wenn ein Benutzer höchstens ein Mal in der Tabelle antworten vorkommt:

    Also jede User-ID kommt in der Tabelle antworten 30 mal vor, weil ja jede der 30 Antworten mit samt der User-ID abgespeichert wird.
    In der Tabelleusers kommt die ID nun nur einmal vor.

    Der Mensch, der das hier anfangs programmiert hat, wollte das irgendwie mir folgernder Abfrage lösen:

    PHP
    $sql='SELECT * FROM antworten AS ant, users AS u WHERE u.id = ant.id ';

    Das gibt aber 30 mal den selben Nutzer mit der dazugehörigen ID aus...

    Ich bräuchte eher so eine Art Befehl wie

    PHP
    $sql='SELECT * FROM users WHERE antworten.id=users.id';


    Aber so geht das natürlich nicht...

    4 Mal editiert, zuletzt von osiris (22. Mai 2008 um 13:19)

  • Das gibt aber 30 mal den selben Nutzer mit der dazugehörigen ID aus...

    Daher auch die Gruppierung, wie von bjelli und mir vorgeschlagen.

    Außerdem macht diese Query einen Inner Join, d.h. es bleiben von beiden beteiligten Tabellen nur die Tupel übrig, die in der jeweils anderen Tabelle eine Entsprechung haben. Du brauchst aber einen Outer Join (siehe oben), damit die User, die noch keine einzige Antwort gegeben haben, auch im Ergebnis enthalten sind.

    Ich bräuchte eher so eine Art Befehl wie

    PHP
    $sql='SELECT * FROM users WHERE antworten.id=users.id';


    Aber so geht das natürlich nicht...

    Code
    select * from users where id in (select id from antworten);

    Damit kriegst du alles User, die in der Antworttabelle vorkommen. Es fehlen aber immer noch die User, die nicht in der Antworttabelle vorkommen. Könnte man so machen:

    Code
    (select id, 'ja' as antwort from users where id in (select id from antworten)) union
    (select id, 'nein' as antwort from users where id not in (select id from antworten));

    Damit kriegst du eine Liste aller User und zusätzlich eine Spalte "antwort", in der "ja" steht, wenn der Benutzer in der Antworttabelle vorkommt, und "nein", wenn der Benutzer in der Antworttabelle nicht vorkommt. Die Variante mit Left Outer Join und Gruppierung würd ich dem aber auf jeden Fall vorziehen.

    Aber was funktioniert an den in den Postings oben vorgeschlagenen Queries nicht?

  • Wenn ich dein Problem richtig verstanden habe, hast du die Funktion mysql_fetch_array falsch verwendet:

    Zitat von http://at.php.net/mysql_fetch_array

    mysql_fetch_array — Liefert einen Datensatz als assoziatives Array, als numerisches Array oder beides

  • Danke für den Tipp.

    ich habe die ganze Sache jetzt mal auf relativ dilettantische Weise mit "Riesen-Array" gelöst.
    Das hat zumindest den Vorteil, dass ich genau verstehe, was da passiert.

    Vielleicht versuch ich das auch nochmal mit der cleveren Variante, wenn Zeit bleibt.

    Danke für eure Hilfe!

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!