2009-07-30 10 views
6

J'ai trois tables de base:MySQL Choisir REJOIGNEZ 3 tables

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 

Essentiellement, ce que je suis en train de faire est de créer une boîte de réception. Donc, si usrID 2 (Bill Jones) ouvre sa boîte de réception, il verra qu'il a 2 non lus (d'où les messages 'is_read') (threads # 111 et # 222). Fondamentalement, j'ai besoin de savoir comment configurer mon instruction SELECT pour joindre les trois tables (la relation entre pm_data et pm_info provoque l'information du message, tandis que la relation entre tblUsers et pm_data provoque le 'display name' de l'expéditeur), pour afficher le thread le plus récent (par horodatage?) en haut.

Ainsi, nous verrions quelque chose comme ceci:

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

Espérons que cela a du sens! Merci pour toute aide!

EDIT: Voici ma dernière réponse:

Je pris les conseils de monnaies locales, et a fait la relation entre les deux tables en fonction id (ajouté une colonne appelée « message_id » à pm_info).

Ensuite, peaufiné l'instruction MySQL autour d'un peu pour arriver à ceci:

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 

Cela semble fonctionner pour moi (jusqu'à présent).

Répondre

9

Vous aurez besoin de deux jointures. Quelque chose comme ce qui suit devrait vous commencer (bien que je ne comprends pas 100% la relation entre pm_data et 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 

Je suppose que la relation entre pm_data et pm_info est l'identifiant du fil. Si ce n'est pas le cas, vous devriez être en mesure d'ajuster ce qui précède à ce dont vous avez besoin. J'ai également trié par date envoyé ici, mais il ne gardera pas les fils ensemble. Je ne suis pas sûr si vous voulez les garder ensemble ou pas de la façon dont vous avez formulé votre question.


Si vous voulez garder fils ensemble, vous aurez besoin d'une requête plus compliquée:

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 

Cette requête utilise un sous-sélection pour trouver la dernière date de modification pour chaque fil, puis trie par ce premier.

+0

Merci, pour votre réponse. Votre requête compliquée est certainement la direction que je suis en train de prendre. Il ne lance aucune erreur, mais il fait quelques choses: 1) Il montre toujours toutes les parties du fil (même les éléments envoyés par l'utilisateur concernant le fil) et 2) Il montre en double. Faites-moi savoir si vous avez besoin que je sois plus explicite. Merci. – Dodinas

+0

@Dodinas 1) Il montrera toutes les parties du fil. Si vous ne voulez pas tout montrer, vous devrez penser exactement à ce que vous voulez filtrer et l'ajouter à la clause WHERE. Il pourrait aussi y avoir plus dans la relation entre 'pm_data' et' pm_info' qui me manque, parce que tout ce que je dois faire en ce moment c'est l'ID de thread ... 2) Pouvez-vous poster un peu plus de tables ' contenu afin que je puisse voir où cela pourrait aller mal? INNER JOINs ne doit pas produire de lignes en double. C'est peut-être aussi votre erreur est dans le PHP après l'exécution de la requête ... –

+0

@lc: Merci pour la réponse. Fondamentalement, je ne pense pas que le problème est avec le PHP. Cependant, cela pourrait être un problème avec la façon dont ma base de données est structurée. Fondamentalement, ce que j'ai posté est les tables avec lesquelles je travaille. Le 'thread_id' est la seule chose qui relie les deux tables. Peut-être que je dois changer ma structure db? – Dodinas

3

Pour obtenir la liste des messages pour un utilisateur avec qui et quand ils l'ont envoyé, vous pouvez utiliser la requête suivante:

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 

Cela profite du fait que vous peut se joindre à une table à lui-même (ici, tblUsers apparaît deux fois: Une fois pour le destinataire, et encore pour l'expéditeur).

Si vous souhaitez afficher uniquement les messages non lus, vous pouvez mettre and i.IsRead = 0 dans la clause where.