2009-07-30 18 views
6

Mam trzy podstawowe tabele:Wybierz JOIN MySQL 3 Tabele

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 

Zasadniczo, co próbuję zrobić, to utworzyć skrzynki odbiorczej.

Tak więc, jeśli usrID 2 (Bill Jones) otworzy swoją skrzynkę odbiorczą, zobaczy, że on 2 nieprzeczytane (stąd kolumny "is_read") (wątki # 111 i # 222).

Zasadniczo, potrzebuję wiedzieć, jak ustawić moją instrukcję SELECT do JOIN wszystkie trzy tabele (relacja między pm_data i pm_info przynosi informacje o wiadomości, podczas gdy relacja między tblUsers i pm_data powoduje "wyświetlaną nazwę" nadawca), aby wyświetlić ostatni wątek (według datownika?) na górze.

Zatem chcielibyśmy zobaczyć coś takiego:

<?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> 

Mam nadzieję, że to ma sens! Dzięki za pomoc!

EDIT: Oto moja ostateczna odpowiedź:

Wziąłem porady LC, a wykonane relacji między dwiema tabelami na podstawie identyfikatora (dodaje kolumnę o nazwie „message_id” do pm_info).

Następnie manipulowane oświadczenie MySQL wokół trochę wymyślić to:

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 

To wydaje się działać dla mnie (do tej pory).

Odpowiedz

9

Potrzebujesz dwóch złączeń. Coś jak poniżej powinno Ci zacząć (choć nie 100% zrozumieć związek między pm_data i pm_info):

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 

Jestem zakładając związek między pm_data i pm_info jest id wątek. Jeśli tak nie jest, powinieneś być w stanie dostosować powyższe do tego, czego potrzebujesz. Posortowałem także według daty wysłanej tutaj, ale nie będzie utrzymywać wątków razem. Nie jestem pewien, czy chcesz zachować je razem, czy nie, w sposób, w jaki sformułowałeś swoje pytanie.


Jeśli chcesz zachować wątki razem, musisz bardziej skomplikowane zapytania:

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 

Ta kwerenda używa podselekcji znaleźć ostatnią datę zmodyfikowane dla każdego wątku, a następnie sortuje według tego pierwszego.

+0

Dzięki lc, za odpowiedź. Twoje skomplikowane zapytanie to zdecydowanie kierunek, w którym zmierzam. Nie wyrzuca żadnych błędów, ale robi kilka rzeczy: 1) W dalszym ciągu pokazuje wszystkie części wątku (nawet wysłane przez użytkownika elementy związane z wątkiem) i 2) Pokazuje je w duplikatach. Daj mi znać, jeśli chcesz, żebym był bardziej konkretny. Dzięki. – Dodinas

+0

@Dodinas 1) Pokaże wszystkie części wątku. Jeśli nie chcesz pokazać wszystkiego, musisz pomyśleć, co dokładnie chcesz odfiltrować i dodać do klauzuli WHERE. Może być także więcej w związku między 'pm_data' i' pm_info', którego mi brakuje, ponieważ wszystko, co muszę teraz przejść, to identyfikator wątku ... 2) Czy możesz opublikować trochę więcej tabel? treści, więc mogę zobaczyć, gdzie to może pójść źle? INNER JOIN nie powinien tworzyć żadnych wierszy w dwóch egzemplarzach. Prawdopodobnie jest to również twój błąd w PHP po wykonaniu zapytania ... –

+0

@lc: Dzięki za odpowiedź. Zasadniczo nie sądzę, że problem jest z PHP. Jednak może to być problem związany ze strukturą mojej bazy danych. Zasadniczo, to, co napisałem, to tabele, z którymi pracuję. "Thread_id" jest jedyną rzeczą, która odnosi się do dwóch tabel. Być może muszę zmienić moją strukturę db? – Dodinas

3

Aby uzyskać listę wiadomości dla danego użytkownika oraz kto i kiedy wysłał go, można użyć następującego zapytania:

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 

ta wykorzystuje fakt, że może dołączyć tabelę dla siebie (tutaj, tblUsers pojawia się dwa razy: raz dla odbiorcy, i ponownie dla nadawcy).

Jeśli chcesz zobaczyć tylko nieprzeczytane wiadomości, możesz umieścić and i.IsRead = 0 w klauzuli where.