2009-07-30 20 views
6

Ho tre tabelle di base:MySQL selezionare Entra 3 Tavole

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 

In sostanza, quello che sto cercando di fare è creare una casella di posta.

Quindi, se usrID 2 (Bill Jones) apre la sua casella di posta, vedrà che ha 2 messaggi non letti (da cui i messaggi 'is_read') (thread # 111 e # 222).

Fondamentalmente, ho bisogno di sapere come impostare la mia istruzione SELECT per UNIRE tutte e tre le tabelle (la relazione tra pm_data e pm_info comporta le informazioni del messaggio, mentre la relazione tra tblUsers e pm_data determina il 'nome visualizzato' di il mittente), per mostrare il thread più recente (per timestamp?) in cima.

Quindi, vorremmo vedere qualcosa di simile:

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

Speriamo che questo ha un senso! Grazie per qualsiasi aiuto!

EDIT: Ecco la mia risposta definitiva:

ho preso il consiglio di lc, e fece la relazione tra le due tabelle in base all'ID (aggiunta una colonna chiamata 'message_id' a pm_info).

Poi, ottimizzato la dichiarazione MySQL intorno un po 'a venire con questo:

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 

Questo sembra funzionare per me (finora).

risposta

9

Avrete bisogno di due join. Qualcosa di simile alla seguente dovrebbe iniziare (anche se non al 100% capire il rapporto tra pm_data e 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 

che sto assumendo la relazione tra pm_data e pm_info è solo l'ID. Se non lo è, dovresti essere in grado di adattare quanto sopra a qualsiasi cosa ti serva. Ho anche ordinato per data inviata qui, ma non manterrà i thread insieme. Non sono sicuro se vuoi mantenerli insieme o meno dal modo in cui hai espresso la tua domanda.


Se si desidera mantenere le discussioni insieme, avrete bisogno di una query più complessa:

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 

Questa query utilizza un sub-SELECT per trovare il più recente data di modifica per ogni thread, quindi Ordina per questo prima.

+0

Grazie lc, per la risposta. La tua domanda complicata è sicuramente la direzione che sto seguendo. Non sta generando alcun errore, ma sta facendo un paio di cose: 1) Mostra ancora tutte le parti del thread (anche gli elementi inviati dall'utente relativi al thread) e 2) Lo sta mostrando in duplicati. Fammi sapere se hai bisogno che io sia più esplicito. Grazie. – Dodinas

+0

@Dodinas 1) Mostrerà tutte le parti del thread. Se non vuoi mostrare tutto, dovrai pensare a cosa esattamente vuoi filtrare e aggiungerlo alla clausola WHERE. Ci potrebbe essere anche di più nella relazione tra pm_data' e 'pm_info' che mi manca, perché tutto quello che devo andare adesso è l'ID del thread ... 2) Puoi pubblicare un po 'di più dei tavoli? contenuti in modo da poter vedere dove questo potrebbe andare storto? I JOIN INTERNI non dovrebbero produrre righe in duplicato. È anche possibile che il tuo errore sia nel PHP dopo aver eseguito la query ... –

+0

@lc: Grazie per la risposta. Fondamentalmente, non penso che il problema sia con il PHP. Tuttavia, potrebbe essere un problema con il modo in cui il mio db è strutturato. Fondamentalmente, quello che ho postato sono i tavoli con cui lavoro. Il 'thread_id' è l'unica cosa che mette in relazione le due tabelle. Forse ho bisogno di apportare una modifica alla mia struttura db? – Dodinas

3

per ottenere l'elenco dei messaggi per un utente con chi e quando lo ha inviato, è possibile utilizzare la seguente query:

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 

Questa sfrutta il fatto che si può unirsi a un tavolo a se stesso (qui, tblUsers compare due volte: una volta per il destinatario e un'altra per il mittente).

Se si desidera visualizzare solo i messaggi non letti, è possibile inserire and i.IsRead = 0 nella clausola where.