0

My "messages" table has the following fields:

messageid, idto, idfrom, content, and timeSent.

I want my mailbox page to group all of the mails from each individual person (idfrom) and only print the most recent one from each of them. The idea here is that the most recent "conversation" will be at the top of the users mailbox.

I have been googling for hours trying to find a solution. Some claim you need a NATURAL JOIN. Some claim LEFT JOIN. Some have a bunch of frustrating symbols, or "aliases" with no explanation as to where they are defined in your script, e.g. n1.* c2.*.

I have already tried GROUP BY, but it draws randomly (sometimes grabbing older messages and not the most recent one). My current query is below:

"SELECT * FROM messages WHERE idto=$id ORDER BY timeSent DESC LIMIT 100"

Again, using "GROUP BY" will sometimes omit the most recent mail, which is the opposite of what I want.

EDIT: Problem Solved (by not using any additional SQL): Instead of modifying my query, I went with good old PHP and reduced the execution time by a significant amount. Here's how:

  1. Before the "fetch array" loop, I created a variable and made it an empty array ($var = array();)

  2. After that, I made an if statement at the beginning of the FETCH_ARRAY() loop and enclosed all of my previous code into it. (if(!in_array($q['idfrom'], $var))). So, if my user's ID is not already in the array, it will proceed. If it's already there, it will skip on and keep moving through the loop.

  3. At the end of a successful loop (the one that the if statement allowed to pass), I added "array_push($var, $q['idfrom']);"

Meaning, the user's ID is added to the array so that if one of their messages are selected again, the loop skips it.

Viola, it successfully prints the most recent mail from each user with only 3-5 lines of additional PHP code. It's also very modifiable for other purposes as long as your desired condition draws the correct table first, as it will ignore the rest. Make sure your ordering is correct.

I would like to thank everyone for the help and I hope this will save a lot of people a lot of time like it did for me. It was my initial thought, but I felt that using a query may have been the "right" way to do it and decided to ask here.

4

2 回答 2

0

您可以通过查询直接执行此操作。这是一个例子:

select m.*
from messages m
where m.timeSent = (select max(m2.timeSent) from message m2 where m2.idFrom = m.idFrom)

如果您在 `messages(idFrom, timeSent) 上有一个索引,这将具有合理的性能。

于 2013-08-09T01:53:57.547 回答
0

您必须使用一个临时表,该表通过 toId 和 timeSent 对您的消息进行预排序

然后将此临时表加入到消息中

例如,创建一个包含数据的表

CREATE TABLE messages
(
messageId integer,
idTo integer,
idFrom integer,
timeSent datetime,
content varchar(255)
);

insert into messages values (1,11,1,'2013-07-11','first message to user 11');
insert into messages values (2,12,1,'2013-07-03','fist message to user 12');
insert into messages values (3,11,1,'2013-07-12','second message to user 11');
insert into messages values (4,12,1,'2013-07-05','second message to user 12');
insert into messages values (5,13,1,'2013-07-10','second message to user 13');
insert into messages values (6,13,1,'2013-07-09','first message to user 13');

然后查询两个连接表

CREATE TEMPORARY TABLE t1 AS (SELECT idTo, max(timeSent) as timeSent from messages group by idTo);

select m.idFrom, m.idTo, m.timeSent, m.content from t1
join messages m on t1.idTo = m.idTo
and t1.timeSent = m.timeSent;

...并得到这个结果

idFrom        idTo      timeSent                content
1             11        2013-07-12 00:00:00     second message to user 11
1             12        2013-07-05 00:00:00     second message to user 12
1             13        2013-07-10 00:00:00     second message to user 13
  • 杰夫·韦斯
于 2013-08-09T00:09:56.790 回答