2009-07-30 15 views
6

Ich habe drei Basistabellen:MySQL Select JOIN 3 Tabellen

tblUsers: 

    usrID  usrFirst  usrLast 
     1  John   Smith 
     2  Bill   Jones 
     3  Jane   Johnson 

pm_data: 

id  date_sent    title   sender_id thread_id   content 
2 2009-07-29 18:46:13  Subject 1   1   111  Message 2! 
3 2009-07-29 18:47:21  Another Subject  1   222  Message 3! 

pm_info: 

id thread_id receiver_id is_read 
1  111   2   0 
2  111   3   0 
3  222   2   0 
4  222   3   0 

Im Grunde, was ich versuche zu tun, einen Posteingang erstellen.

Also, wenn usrID 2 (Bill Jones) seinen Posteingang öffnet, wird er sehen, dass er 2 ungelesene (daher die 'is_read' Spalte) Nachrichten (Threads # 111 und # 222).

Im Grunde muss ich wissen, wie ich meine SELECT-Anweisung zu JOIN allen drei Tabellen einrichten (die Beziehung zwischen pm_data und pm_info bringt die Nachricht Info, während die Beziehung zwischen tblUsers und pm_data bringt den 'Anzeigenamen' von der Absender), um den neuesten (nach Zeitstempel?) Thread oben anzuzeigen.

So würden wir so etwas wie dies sehen:

<?php $usrID = 2; ?> 

<table id="messages"> 
    <tr id="id-2"> 
    <td> 
    <span> 
    From: John Smith 
    </span> 
    <span>2009-07-29 18:47:21</span> 
    </td> 
<td> 
<div>Another subject</div> 
</td></tr> 
<tr id="id-1"> 
<td> 
    <span> 
    From: John Smith 
    </span> 
    <span>2009-07-29 18:46:13</span> 
</td> 
<td> 
    <div>Subject 1</div> 
</td></tr> 
</table> 

Hoffentlich macht Sinn! Danke für jede Hilfe!

EDIT: Hier ist meine letzte Antwort:

I lc Rat nahm, und machte die Beziehung zwischen den beiden Tabellen basierend auf ID (hinzugefügt, um eine Spalte ‚message_id‘ genannt pm_info).

Dann zwickte die MySQL-Anweisung um ein wenig mit diesem zu kommen:

SELECT pm_info.is_read, sender.usrFirst as sender_name, 
pm_data.date_sent, pm_data.title, pm_data.thread_id 
FROM pm_info 
INNER JOIN pm_data ON pm_info.message_id = pm_data.id 
INNER JOIN tblUsers AS sender ON pm_data.sender_id = sender.usrID 
WHERE pm_data.date_sent IN(SELECT MAX(date_sent) FROM pm_data WHERE pm_info.message_id = pm_data.id GROUP BY thread_id) AND pm_info.receiver_id = '$usrID' ORDER BY date_sent DESC 

Das ist für mich zu funktionieren scheint (bisher).

Antwort

9

Sie benötigen zwei Joins.

SELECT pm_info.is_read, sender.usrFirst + ' ' + sender.usrLast as sender_name, 
    pm_data.date_sent, pm_data.title, pm_data.thread_id 
FROM pm_info 
INNER JOIN pm_data ON pm_info.thread_id = pm_data.thread_id 
INNER JOIN tblUsers AS sender ON pm_data.sender_id = tblUsers.usrID 
WHERE pm_info.receiver_id = @USER_ID /*in this case, 2*/ 
ORDER BY pm_data.date_sent DESC 

Ich gehe davon aus, das die Beziehung zwischen pm_data und pm_info ist der Thread-ID: So etwas wie die folgenden sollten Sie (obwohl ich nicht 100% verstehen die Beziehung zwischen pm_data und pm_info) beginnen. Wenn dies nicht der Fall ist, sollten Sie in der Lage sein, das Obenstehende an alles anzupassen, was Sie brauchen. Ich habe auch nach Datum sortiert hier gesendet, aber wird es nicht die Threads zusammen halten. Ich bin mir nicht sicher, ob du sie zusammenhalten willst oder nicht, wie du deine Frage formuliert hast.


Wenn Sie Fäden zusammen halten wollen, müssen Sie eine kompliziertere Abfrage:

SELECT pm_info.is_read, sender.usrFirst + ' ' + sender.usrLast as sender_name, 
    pm_data.date_sent, pm_data.title, pm_data.thread_id 
FROM pm_info 
INNER JOIN pm_data ON pm_info.thread_id = pm_data.thread_id 
INNER JOIN tblUsers AS sender ON pm_data.sender_id = tblUsers.usrID 
INNER JOIN (SELECT thread_id, MAX(date_sent) AS max_date 
      FROM pm_data 
      GROUP BY thread_id) AS most_recent_date 
      ON pm_data.thread_id = most_recent_date.thread_id 
WHERE pm_info.receiver_id = @USER_ID /*in this case, 2*/ 
ORDER BY most_recent_date.max_date DESC, pm_data.thread_id, 
    pm_data.date_sent DESC 

Diese Abfrage eine subselect verwendet das neueste Änderungsdatum für jeden Thread zu finden, dann Sortiert nach diesem zuerst.

+0

Danke lc, für Ihre Antwort. Ihre komplizierte Abfrage ist definitiv die Richtung, in die ich gehe. Es wirft keine Fehler auf, aber es macht ein paar Dinge: 1) Es zeigt immer noch alle Teile des Threads (sogar die gesendeten Elemente des Benutzers, die sich auf den Thread beziehen) und 2) Es zeigt es in Duplikaten. Lassen Sie es mich wissen, wenn Sie mich expliziter brauchen. Vielen Dank. – Dodinas

+0

@Dodinas 1) Es werden alle Teile des Threads angezeigt. Wenn Sie nicht alles anzeigen möchten, müssen Sie sich überlegen, was genau Sie ausfiltern und der WHERE-Klausel hinzufügen möchten. Es könnte auch mehr in der Beziehung zwischen "pm_data" und "pm_info" geben, die ich vermisse, denn alles, was ich jetzt tun muss, ist die Thread-ID ... 2) Kannst du etwas mehr von den Tabellen posten? Inhalt, damit ich sehen kann, wo das schief gehen könnte? INNER JOINs sollten keine doppelten Zeilen erzeugen. Es ist auch möglich, dass Ihr Fehler in PHP nach der Ausführung der Abfrage liegt ... –

+0

@lc: Danke für die Antwort. Im Grunde glaube ich nicht, dass das Problem bei PHP liegt. Es könnte jedoch ein Problem mit der Struktur meiner Datenbank sein. Was ich gepostet habe, sind die Tabellen, mit denen ich arbeite. Die 'thread_id' ist das einzige, was die beiden Tabellen betrifft. Vielleicht muss ich meine db-Struktur ändern? – Dodinas

3

Um die Liste der Nachrichten für einen Benutzer zu erhalten zusammen mit wem und wann sie ihn sendeten, können Sie die folgende Abfrage verwenden:

select 
    s.usrFirst + ' ' + s.usrLast as SenderName, 
    m.Title, 
    m.DateSent, 
    i.IsRead 
from 
    tblUsers r 
    inner join pm_info i on 
     r.receiver_id = i.receiver_id 
    inner join pm_data m on 
     i.thread_id = m.thread_id 
    inner join tblUsers s on 
     m.sender_id = s.userID 
where 
    r.usrid = @id 

Dieser Vorteil der Tatsache Rechnung, dass Sie einen Tisch beitreten zu sich selbst (hier, tblUsers erscheint zweimal: Einmal für den Empfänger und wieder für den Absender). Wenn Sie nur ungelesene Nachrichten sehen möchten, können Sie and i.IsRead = 0 in die where-Klausel einfügen.