Scanty ... but doable. Build the answer one piece at a time.
Building a query - step by step
Given the specific reference user (“I”) in the examples, you need to find all the messages between “me” and the other person. For each such other person, you want to find one message with the most recent time stamp.
Request 1
Allows you to set the conversation ID by linking all messages together. Since we are interested in one side (“I”) at a time, we can use the identifier of the other person to identify the conversation.
SELECT m.recipient_uid AS conversation, m.recipient_uid AS recipient_uid, m.sender_uid AS sender_uid, m.timestamp AS timestamp FROM mesg AS m WHERE m.sender_uid = '$myID' UNION SELECT m.sender_uid AS conversation, m.recipient_uid AS recipient_uid, m.sender_uid AS sender_uid, m.timestamp AS timestamp FROM mesg AS m WHERE m.recipient_uid = '$myID'
This allows you to scroll through all the chats along with the same conversation id.
Request 2
Now you need to group this by conversation in order to find the conversation and most recently; for this you do not need other columns (recipient_uid or sender_uid):
SELECT conversation, MAX(timestamp) AS max_timestamp FROM (SELECT m.recipient_uid AS conversation, m.timestamp AS timestamp FROM mesg AS m WHERE m.sender_uid = '$myID' UNION SELECT m.sender_uid AS conversation, m.timestamp AS timestamp FROM mesg AS m WHERE m.recipient_uid = '$myID') AS c GROUP BY conversation
Request 3
So, for every conversation, we now know the latest timestamp. We just need to join this information with a previous request to get most of the details:
SELECT c.recipient_uid, c.sender_uid, c.timestamp FROM (SELECT conversation, MAX(timestamp) AS max_timestamp FROM (SELECT m.recipient_uid AS conversation, m.timestamp AS timestamp FROM mesg AS m WHERE m.sender_uid = '$myID' UNION SELECT m.sender_uid AS conversation, m.timestamp AS timestamp FROM mesg AS m WHERE m.recipient_uid = '$myID') AS c GROUP BY conversation ) AS x JOIN (SELECT m.recipient_uid AS conversation, m.recipient_uid AS recipient_uid, m.sender_uid AS sender_uid, m.timestamp AS timestamp FROM mesg AS m WHERE m.sender_uid = '$myID' UNION SELECT m.sender_uid AS conversation, m.recipient_uid AS recipient_uid, m.sender_uid AS sender_uid, m.timestamp AS timestamp FROM mesg AS m WHERE m.recipient_uid = '$myID' ) AS c ON c.conversation = x.conversation AND c.timestamp = x.max_timestamp
Request 4
Since you said you want to get names, you can expand this to join the user table twice:
SELECT c.recipient_uid, c.sender_uid, c.timestamp, u1.uname AS recipient, u2.uname AS sender FROM (SELECT conversation, MAX(timestamp) AS max_timestamp FROM (SELECT m.recipient_uid AS conversation, m.timestamp AS timestamp FROM mesg AS m WHERE m.sender_uid = '$myID' UNION SELECT m.sender_uid AS conversation, m.timestamp AS timestamp FROM mesg AS m WHERE m.recipient_uid = '$myID') AS c GROUP BY conversation ) AS x JOIN (SELECT m.recipient_uid AS conversation, m.recipient_uid AS recipient_uid, m.sender_uid AS sender_uid, m.timestamp AS timestamp FROM mesg AS m WHERE m.sender_uid = '$myID' UNION SELECT m.sender_uid AS conversation, m.recipient_uid AS recipient_uid, m.sender_uid AS sender_uid, m.timestamp AS timestamp FROM mesg AS m WHERE m.recipient_uid = '$myID' ) AS c ON c.conversation = x.conversation AND c.timestamp = x.max_timestamp JOIN user AS u1 ON u1.uid = c.recipient_uid JOIN user AS u2 ON u2.uid = c.sender_uid
It is fun there. I would not want to write this at a time, but created a piece at a time, it is not too intimidating (although this is not trivial).
Testing scheme
User table
CREATE TABLE user ( uid INTEGER NOT NULL PRIMARY KEY, uname VARCHAR(30) NOT NULL );
Mesg table
DATETIME YEAR TO SECOND is a fun way to write TIMESTAMP (in IBM Informix Dynamic Server - where I tested this).
CREATE TABLE mesg ( recipient_uid INTEGER NOT NULL REFERENCES user(uid), sender_uid INTEGER NOT NULL REFERENCES user(uid), message VARCHAR(255) NOT NULL, timestamp DATETIME YEAR TO SECOND NOT NULL, PRIMARY KEY (recipient_uid, sender_uid, timestamp), READ CHAR(1) NOT NULL );
User data
INSERT INTO USER VALUES(2, 'My Full Name'); INSERT INTO USER VALUES(6, 'Her Full Name'); INSERT INTO USER VALUES(3, 'Dag Brunner');
Mesg data
INSERT INTO mesg VALUES(2, 6, 'I like you, more than ghoti', '2008-01-01 00:05:03', 1); INSERT INTO mesg VALUES(2, 6, 'I like you, more than fish', '2011-01-15 13:45:09', 1); INSERT INTO mesg VALUES(6, 2, 'Hey, wanna go fish?', '2008-01-01 09:30:47', 0); INSERT INTO mesg VALUES(2, 3, 'Wanna catch a beer?', '2011-01-14 13:45:09', 1); INSERT INTO mesg VALUES(3, 2, 'Sounds good to me!!', '2011-01-14 13:55:39', 1); INSERT INTO mesg VALUES(3, 6, 'Heading home now???', '2010-12-31 12:27:41', 1); INSERT INTO mesg VALUES(6, 3, 'Yes - on the bus!!!', '2010-12-31 13:55:39', 1);
Results 1
Conv Recv Send When 3 2 3 2011-01-14 13:45:09 3 3 2 2011-01-14 13:55:39 6 2 6 2008-01-01 00:05:03 6 2 6 2011-01-15 13:45:09 6 6 2 2008-01-01 09:30:47
Results 2
Conv Most Recent 3 2011-01-14 13:55:39 6 2011-01-15 13:45:09
Results 3
Recv Send When 3 2 2011-01-14 13:55:39 2 6 2011-01-15 13:45:09
Results 4
Recv Send When Receiver Sender 3 2 2011-01-14 13:55:39 Dag Brunner My Full Name 2 6 2011-01-15 13:45:09 My Full Name Her Full Name
Wow, I don’t often get a piece of SQL that is this complicated right the first time, but in this case, in addition to riding the receiver_uid vs recipient_uid method on the first iteration, it really worked right the first time.
Common decision
Omitting the “who” parameter (or “me” or “$ myID”), we can find a common solution for the last message in any of the conversations between two people. The conversation is determined by the identifier of the participant with a higher and lower (or vice versa). Otherwise, it is very similar to the previous one.
SELECT c.recipient_uid, c.sender_uid, c.timestamp, u1.uname AS recipient, u2.uname AS sender FROM (SELECT conv01, conv02, MAX(timestamp) AS max_timestamp FROM (SELECT m.recipient_uid AS conv01, m.sender_uid AS conv02, m.timestamp AS timestamp FROM mesg AS m WHERE m.sender_uid < m.recipient_uid UNION SELECT m.sender_uid AS conv01, m.recipient_uid AS conv02, m.timestamp AS timestamp FROM mesg AS m WHERE m.sender_uid > m.recipient_uid ) AS C GROUP BY conv01, conv02 ) AS x JOIN (SELECT m.recipient_uid AS conv01, m.sender_uid AS conv02, m.recipient_uid AS recipient_uid, m.sender_uid AS sender_uid, m.timestamp AS timestamp FROM mesg AS m WHERE m.sender_uid < m.recipient_uid UNION SELECT m.sender_uid AS conv01, m.recipient_uid AS conv02, m.recipient_uid AS recipient_uid, m.sender_uid AS sender_uid, m.timestamp AS timestamp FROM mesg AS m WHERE m.sender_uid > m.recipient_uid ) AS C ON c.conv01 = x.conv01 AND c.conv02 = x.conv02 AND c.timestamp = x.max_timestamp JOIN USER AS u1 ON u1.uid = C.recipient_uid JOIN USER AS u2 ON u2.uid = C.sender_uid;
Result with Sample Data
Recv Send When Recipient Sender 6 3 2010-12-31 13:55:39 Her Full Name Dag Brunner 2 6 2011-01-15 13:45:09 My Full Name Her Full Name 3 2 2011-01-14 13:55:39 Dag Brunner My Full Name