views:

63

answers:

3

How can I formulate a query for the below task:

Let's say you are logged in as user:1 I want to get one row per conversations I've had. For each row I want to get, the "Subject" of the first row within the conversation "DateTime" of the first row "Message" last message of this conversation no matter who wrote it

CREATE TABLE messages (
    ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    FromID INT NOT NULL,   
    ToID INT NOT NULL,    
    ConversationID INT NOT NULL,    
    Subject varchar(255), 
    Message varchar(255),
    DateTime DATETIME                                       
    ) ENGINE=InnoDB;


CREATE TABLE conversations (
    ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY                                    
    ) ENGINE=InnoDB;



INSERT INTO conversations (ID) VALUES (1), (2), (3);
INSERT INTO messages (FromID, ToID, ConversationID, Subject, Message, DateTime) VALUES (1,2, 1, "Hi", "This is a test message", "2010-08-08 16:23:48");        
INSERT INTO messages (FromID, ToID, ConversationID, Subject, Message, DateTime) VALUES (1,2, 1, "", "Hey again you have not answered", "2010-08-08 16:23:52");                                                                                                                                               
INSERT INTO messages (FromID, ToID, ConversationID, Subject, Message, DateTime) VALUES (2,1, 1, "", "Hi this is my answer", "2010-08-08 16:23:59");


INSERT INTO messages (FromID, ToID, ConversationID, Subject, Message, DateTime) VALUES (2,1, 2, "2.Hi", "2.This is a test message", "2010-08-08 16:25:48");        
INSERT INTO messages (FromID, ToID, ConversationID, Subject, Message, DateTime) VALUES (1,2, 2, "", "2.Hi back", "2010-08-08 16:25:52");                                                                                                                                               
INSERT INTO messages (FromID, ToID, ConversationID, Subject, Message, DateTime) VALUES (2,1, 2, "", "2.Hi this is my answer", "2010-08-08 16:25:59");


INSERT INTO messages (FromID, ToID, ConversationID, Subject, Message, DateTime) VALUES (2,1, 3, "3.Hi", "3.This is a test message", "2010-08-08 16:27:48");        
INSERT INTO messages (FromID, ToID, ConversationID, Subject, Message, DateTime) VALUES (1,2, 3, "", "2.Hi back", "2010-08-08 16:27:52");   
INSERT INTO messages (FromID, ToID, ConversationID, Subject, Message, DateTime) VALUES (1,2, 3, "", "2.Hello are you there?", "2010-08-08 16:27:59");                                                                                                                                            

+1  A: 

Take a look @ ROW_NUMBER() in MySQL - you'll be able to apply this to your problem for sure.

Will A
+1  A: 
SELECT M.ConversationID, 
MAX(CASE WHEN M.DateTime = X.FirstRow THEN M.Subject END) AS Subject,
CAST(COALESCE(MAX(CASE WHEN M.DateTime = X.LastRowSentByOtherUser 
                       THEN M.DateTime END),X.LastRow) AS DateTime)AS LastTime,
MAX(CASE WHEN M.DateTime = X.LastRow THEN M.Message END) AS Message,
MAX(CASE WHEN FromID = 1 THEN ToID ELSE FromID END) AS OtherParticipantId
FROM messages M
JOIN (
    SELECT ConversationID, MIN(DateTime) AS FirstRow, MAX(DateTime) AS LastRow,
    MAX(CASE WHEN FromID<>1 THEN DateTime END) AS LastRowSentByOtherUser
    FROM messages
    WHERE FromID=1 OR ToID=1
    GROUP BY ConversationID
) X ON X.ConversationID = M.ConversationID
AND (M.DateTime IN (X.FirstRow, X.LastRow, X.LastRowSentByOtherUser))
GROUP BY M.ConversationID
HAVING MAX(CASE WHEN M.DateTime = X.LastRowSentByOtherUser 
                   THEN M.DateTime END) IS NOT NULL
Martin Smith
Hi Martin this is nice!!Just couple things, the Message i'm getting is not the latest one from the conversation and the DateTime i'm actually really looking for is the time of the last message sent by the other user in this conversation.
I think the issue might be the `NOW()` in your test table meaning all datettimes are the same? If so the id could be used instead.
Martin Smith
Yap that was it! This is almost perfect, I edited the post with new data. Last thing how can I also get the ID of the user that's having conversation with me also for each row (conversation)
I think my edit *should* work for the clarified spec obviously test it against some data though!
Martin Smith
wow :) would not have figured this out that thanks so much, sorry to add something I just realized now, but could I also get the ID of the user im having conversation with for each returned row?
That's what the `OtherParticipantId` column is meant to do...
Martin Smith
Thank you so much Martin its perfect!!! Also I added one line to tweak because I only want to show the conversations where the other user actually answered otherwise the message i sent will only be visible in my outbox. So I added at the endHAVING COUNT(*) > 1Is that good way of doing this?
`HAVING MAX(CASE WHEN M.DateTime = X.LastRowSentByOtherUser THEN M.DateTime END) IS NOT NULL` would do this. (I'm not sure if the message can be sent in the same direction twice in a row which could mean the COUNT is > 1 but there is no response from the other user?)
Martin Smith
Basically if you send a message and the person doesn't answer, you don't see that conversation in your inbox its only in your sentbox but from your sentbox you can only forward not replymeaning if the same user wants to message again he has to create a new message i.e new conversation.Is this good behavior you think?
+1  A: 

You should try something like this:

SELECT 
   m1.Subject,
   m1.DateTime,
   m2.Message
FROM conversations c 
INNER JOIN 
   (SELECT MIN(ID) AS minID, 
           MAX(ID) AS maxID, 
           ConversationID
   FROM messages
   WHERE FromID = @userID OR ToID = @userID
   GROUP BY ConversationID) AS cGrouped
ON c.ConversationID = cGrouped.ConversationID
INNER JOIN messages m1 ON m1.ID = cGrouped.minID
INNER JOIN messages m2 ON m2.ID = cGrouped.maxID
gyromonotron