Chef: PHP MySQL 2 Tabellen Abfrage

Hallo,

arbeite gerade an einer kleinen Webseite mit einem Privaten Nachrichten System (Komplett in AJAX). Es werden alle Mitglieder angezeigt bei "Private Nachrichten" dann kann man ein Benutzer anklicken und rechts daneben werden dann die Nachrichten angezeigt. Nun will ich aber das er die Benutzer sortiert:

Die Benutzer die man bereits geschrieben hat, sollen oben angezeigt werden. Und zusätzlich nach dem Datum (Letzte Nachricht). Habe 2 Tabellen members und pm folgender Aufbau:

member (id, name, pic, datum, online, ...)
pm (id, from, to, datum, content, read)

Keine Ahnung wie ich das anstellen soll, hatte schon immer Probleme - abfragen mit 2 Tabellen.

  1. In etwa so stelle ich mir das vor:

    $sql = "SELECT members.id, members.name, members.pic FROM members,pm WHERE (pm.from=members.id AND pm.to='".$_SESSION["myid"]."') GROUP BY pm.datum DESC";

    Natürlich sind jetzt noch doppelte Einträge vorhanden wenn ich DISTINCT verwende stimmt aber die Sortierung nicht mehr. Problem hier ist auch, dass er nur die Benutzer anzeigt die man bereits geschrieben hat - was klar ist.

    Nur wie mache ich das anders?

    1. Tach!

      In etwa so stelle ich mir das vor:

      $sql = "SELECT members.id, members.name, members.pic FROM members,pm WHERE (pm.from=members.id AND pm.to='".$_SESSION["myid"]."') GROUP BY pm.datum DESC";

      Natürlich sind jetzt noch doppelte Einträge vorhanden wenn ich DISTINCT verwende stimmt aber die Sortierung nicht mehr.

      Wenn du dopplete Einträge mit DISTICT zu bekämpfen versuchst, ist das oftmals ein Zeichen dafür, dass der Join verbesserungswürdig ist oder du anderweitig eine zu große Datenmenge abgefragt hast.

      Eine Einführung in Joins, besonders wenn du schon immer damit Probleme hast, sollte dir generell beim Verständnis helfen.

      Problem hier ist auch, dass er nur die Benutzer anzeigt die man bereits geschrieben hat - was klar ist.

      Bei einem (impliziten) Inner Join bekommst du nur Ergebnisse, wenn in beiden Tabelle Daten vorhanden sind. Outer Joins liefern auch die Daten der einen Tabelle, wenn die andere nichts hat.

      Die Benutzer die man bereits geschrieben hat, sollen oben angezeigt werden. Und zusätzlich nach dem Datum (Letzte Nachricht).

      Du willst also eigentlich von der pm-Tabelle nur das Datum der neuesten Nachricht haben. Dann frag einfach dieses ab, aber nicht über einen mit DISTINCT kleingeklopften Join sondern über eine korrelierte (correlated) Subquery.

      SELECT members.zeug, (SELECT MAX(datum) FROM pm WHERE from = members.id AND to = :sessionid) datum FROM members ORDER BY datum

      Außerdem ist es empfehlenswert, PDO (oder mysqli) zu verwenden, und dann die variablen Teile per Prepared Statement zu übergeben. Damit spart man sich das Zusammengestückel der Query und kann auch nicht die Maskierungen für den Kontextwechsel vergessen.

      dedlfix.

      1. Du willst also eigentlich von der pm-Tabelle nur das Datum der neuesten Nachricht haben. Dann frag einfach dieses ab, aber nicht über einen mit DISTINCT kleingeklopften Join sondern über eine korrelierte (correlated) Subquery.

        SELECT members.zeug, (SELECT MAX(datum) FROM pm WHERE from = members.id AND to = :sessionid) datum FROM members ORDER BY datum

        Hallo,

        Danke Dir erstmal. Genau will alle Mitglieder auflisten und die wo man die neuste Nachricht erhalten hat (aus Tabelle pm) sollen oben angezeigt werden z.B.

        Sven (2 Nachrichten, Letzte Nachricht: 10.12.13)
        Natascha (5 Nachrichten, Letzte Nachricht: 10.01.14)
        Dennis (1 Nachricht, Letzte Nachricht: 09.01.14)

        Dann sollen die halt so Sortiert werden:

        1. Natascha
        2. Dennis
        3. Sven

        Der Code von oben sieht ganz gut aus, aber irgendwie hat die Subquery keine Auswirkung.

        Ich schaue mir mal genauer JOINS an. Danke nochmal.

        1. Tach!

          SELECT members.zeug, (SELECT MAX(datum) FROM pm WHERE from = members.id AND to = :sessionid) datum FROM members ORDER BY datum
          Danke Dir erstmal. Genau will alle Mitglieder auflisten und die wo man die neuste Nachricht erhalten hat (aus Tabelle pm) sollen oben angezeigt werden z.B.
          Sven (2 Nachrichten, Letzte Nachricht: 10.12.13)
          Natascha (5 Nachrichten, Letzte Nachricht: 10.01.14)
          Dennis (1 Nachricht, Letzte Nachricht: 09.01.14)

          Dazu fehlt noch die Anzahl der Nachrichten. Die bekommst du so leider nicht mit in die Subquery rein, denn sie steht an einer Stelle, wo nur ein einzelner Wert erlaubt ist.

          Der Code von oben sieht ganz gut aus, aber irgendwie hat die Subquery keine Auswirkung.

          Die Sortierung sollte zumindest schon richtig sein. Und es gibt ein neues Feld in der Ergebnismenge, in meinem Beispiel namens "datum".

          Nun noch das Problem mit dem zweiten Wert. Den gibts mit noch einer Subquery (was nicht so toll ist) oder wenn du sie Subquery ins FROM schreibst.

          SELECT members.zeug, p.datum, p.anzahl  
          FROM members  
          LEFT JOIN (SELECT COUNT(*) anzahl, MAX(datum) datum FROM pm WHERE to = :sessionid) p ON p.from = members.id  
          ORDER BY datum
          

          Aus dem Kopf müsste das so gehen.

          Der Code von oben sieht ganz gut aus, aber irgendwie hat die Subquery keine Auswirkung.

          Beachte, dass ich mit dem :sessionid den Parameter per Prepared Statement übergebe. Wenn du die nicht nimmst, muss du ihn auf herkömmliche Weise reinfummeln.

          dedlfix.

          1. Vielen Dank für die Hilfe. Funktioniert! Der erste Code hatte schon funktioniert von Dir, hatte nur ein Fehler drin. Musste von der Tabelle pm - From und To Abfragen ob es members.id ist.