2013-07-04 5 views
0

J'apprécierais vraiment toute aide essayant de simplifier une requête de MySQL. Le but de la requête est d'extraire les messages d'une table de messages (users_messages) qui contient les colonnes suivantes: message_id, from_id, to_id, message_content, date_sent.Essayer de simplifier une requête MySQL

Les champs from_id et to_id doivent rejoindre une table users (users) contenant ces colonnes: user_id, user_username.

De plus, je dois mentionner qu'il y a une table d'utilisateurs bloqués (users_blocked) qui filtre les messages si la fonction user_id est présente dans cette table. Tout cela fonctionne très bien et les messages sont commandés avec le plus récent en premier, c'est ce que je veux. Mon seul problème est qu'il ne tire pas le 'message_content' correspondant. c'est-à-dire qu'il tire la date la plus récente, mais pas le message le plus récent. Peut-être ai-je besoin d'une approche différente (par exemple des sous-requêtes) mais je ne peux pas comprendre ce qui se passe autour de moi.

Voici la requête:

select m.message_content, 
    if(from_id < to_id, concat(from_id,to_id), concat(to_id,from_id)) as ft, 
    if (from_id = $my_id, to_id, from_id) as other_id, 
    max(date_sent) as most_recent 
from users_messages m 
    left join users_blocked ub1 on (from_id = ub1.blocked_id and ub1.user_id = $my_id) 
    left join users_blocked ub2 on (to_id = ub2.blocked_id and ub2.user_id = $my_id) 
where 
    (from_id = $my_id or to_id = $my_id) 
    and ub1.blocked_id is null 
    and ub2.blocked_id is null 
group by 
    ft 
order by 
    most_recent desc 

Désolé, voici les structures de table:

utilisateurs

user_id user_username 
1   Simon 
2   Amber 
3   Tom

users_messages

 
message_id from_id to_id date_sent    message_content 
1    1   2  2012-07-04 11:52:12 Hello 
2    1   2  2012-07-04 12:32:24 Another message 
3    1   2  2012-07-04 14:00:00 Hello again 

users_blocked

 
user_id blocked_id 
1   3 
+1

S'il vous plaît inclure votre structure de table (s). Aussi - il retourne 'message_content' mais ce n'est pas la bonne valeur? Ou ça ne retourne rien? – ethrbunny

+3

Ce n'est pas trop mal. Enfer, vous pouvez tout lire sans défilement, ce qui est toujours un bonus! –

+0

pas terrible mais je serais probablement juste un tableau d'utilisateurs bloqués et faire un pas pour le from_id – timpone

Répondre

0

Essayez:

select m.message_content, 
     x.ft, 
     x.other_id, 
     x.most_recent 
from (select if(from_id < to_id, concat(from_id,to_id), concat(to_id,from_id)) as ft, 
      if(from_id = $my_id, to_id, from_id) as other_id, 
      max(date_sent) as most_recent 
     from users_messages um 
     left join users_blocked ub1 
     on (um.from_id = ub1.blocked_id and ub1.user_id = $my_id) 
     left join users_blocked ub2 
     on (um.to_id = ub2.blocked_id and ub2.user_id = $my_id) 
     where ub1.blocked_id is null and ub2.blocked_id is null and 
      (um.from_id = $my_id or um.to_id = $my_id) 
     group by ft) x 
join users_messages m 
    on m.date_sent = x.most_recent and 
     m.from_id in ($my_id, x.other_id) and 
     m.to_id in ($my_id, x.other_id) 
order by 
    x.most_recent desc 

SQLFiddle here.

+0

Merci Mark. J'ai essayé ceci et j'ai reçu une erreur "Colonne inconnue 'm.from_id' dans 'where clause'". J'ai changé "users_messages" en "users_messages m" dans la sous-requête et maintenant cela renvoie 0 résultats. –

+0

@SimonKing: J'ai fait quelques changements - essayez maintenant. –

+0

Spot sur. Absolument parfait. Merci beaucoup –

0

Ici, je présume que Simon King veut, le contenu des messages de table users_messages qui comprend la condition suivante,

  1. Les utilisateurs ne doivent pas bloquer soit les directions,
  2. Les messages les plus récents transférés entre les utilisateurs

Ainsi, j'ai modifié la requête Mark Bannister comme suit,

SELECT temp.* FROM (
SELECT um.*, concat(um.from_id,to_id) as direction FROM userMessages um 
LEFT JOIN userBlocked ub1 ON um.from_id = ub1.user_id AND um.to_id = ub1.blocked_id 
LEFT JOIN userBlocked ub2 ON um.to_id = ub2.user_id AND um.from_id = ub2.blocked_id 
WHERE ub1.user_id is null AND ub1.blocked_id is null AND ub2.user_id is null AND ub2.blocked_id is null 
ORDER BY um.date_sent DESC 
) temp 
GROUP BY direction 

violon SQL est http://sqlfiddle.com/#!2/bdc77/1/0

+0

Cela repose sur un comportement observé mais non documenté dans MySQL, qui pourrait ne pas fonctionner dans les futures versions; il a déjà été supprimé de MariaDB (la branche open-source de MySQL). –

+0

@ Mark Bannister, Donnez-moi une adresse pour obtenir plus d'informations à ce sujet –

+0

ici: https://kb.askmonty.org/fr/group-by-trick-has-been-optimized-away/ –

0

Comme je comprends, le principal problème de cette demande est ce résultat ne contient que les premières dates, pas de messages. Pour corriger cela, vous pouvez le faire:

  1. faire ensemble de données préparées qui ont les plus récentes dates:

    select to_id, from_id, max (date_sent) comme most_recent de users_messages m gauche rejoindre ub users_blocked sur ub.user_id = $ my_id et ub.blocked_id en (to_id, from_id) où (from_id = $ my_id ou to_id = $ my_id) et ub.blocked_id est nul groupe par to_id, from_id par ordre décroissant most_recent

je vois vous tâtonnez des données par deux colonnes to_id, from_id. Cette sous-requête n'est pas meilleur endroit pour calculer des choses comme:

if(from_id < to_id, concat(from_id,to_id), concat(to_id,from_id)) as ft 
  1. Ensuite, il suffit de sélectionner d'autres données nécessaires à partir users_messages, qui correspond à notre to_id, from_id et recent_date de la table préparée:

    sélectionner um. * de

    (
    select to_id, from_id, max(date_sent) as most_recent 
    from users_messages m 
    left join users_blocked ub on ub.user_id = 1 
    and ub.blocked_id in (to_id, from_id) 
    where 
    (from_id = 1 or to_id = 1) 
    and ub.blocked_id is null 
    group by 
    to_id, from_id 
    order by 
    most_recent desc 
    ) as prepared_messages 
    left join users_messages um on um.from_id = prepared_messages.from_id 
    and um.to_id = prepared_messages.to_id 
    and um.date_sent = prepared_messages.most_recent 
    
Questions connexes