Given the following:
I need to be able to get a list of all threads in which a given user has participated, sorted by most recent message first, with only the most recent message being displayed (1 message per thread)
This is the SQL query for the above:
SELECT
Message.MessageId,
Message.CreateDate,
Message.Body,
Login.Username,
(SELECT MessageReadState.ReadDate
FROM MessageReadState
WHERE MessageReadState.MessageId = Message.MessageId
AND MessageReadState.LoginId = 2) AS ReadState
FROM Message INNER JOIN Login ON Message.SenderLoginId = Login.LoginId
WHERE Message.MessageId IN (
SELECT Max(Message.MessageId)
FROM MessageThreadParticipant
INNER JOIN Message
ON MessageThreadParticipant.MessageThreadId = Message.MessageThreadId
WHERE MessageThreadParticipant.LoginId=2
GROUP BY MessageThreadParticipant.MessageThreadId
)
ORDER BY Message.CreateDate DESC;
The way this works is this. a Loginid 1 send a LoginId 2 a message:
a new thread is created and a record is inserted into MessageThread
a new record is added into Message table with the treadId from above
TWO records are inserted into MessageThreadParticipant (Sender LoginId and Recipient LogiId)
When a user opens his/hers list of messages MessageReadState will update ReadDate of the message.
QUESTION: I would like to create a view where I can simply filter on LoginId (I would be using LINQ). However I can’t do this with the Query above (since i would need to pass loginId somewhere within the sql statement). Is there anyway to modify the above SQL query in such way that would allow me to have a view?? what is it?
EDIT: i think i have it but i’m not sure if this is the best/most efficient solution:
SELECT
Message.MessageId,
Message.MessageThreadId,
Message.SenderLoginId,
Mtp.LoginId,
Login.Username,
Message.CreateDate,
Message.Body,
(SELECT MessageReadState.ReadDate
FROM MessageReadState
WHERE MessageReadState.MessageId = Message.MessageId
AND MessageReadState.LoginId = Mtp.LoginID) AS ReadState
FROM Message
INNER JOIN Login ON Message.SenderLoginId = Login.LoginId
INNER JOIN MessageThreadParticipant Mtp ON Mtp.MessageThreadId = Message.MessageThreadId
WHERE Message.MessageId IN (
SELECT Max(Message.MessageId)
FROM MessageThreadParticipant
INNER JOIN Message
ON MessageThreadParticipant.MessageThreadId = Message.MessageThreadId
WHERE MessageThreadParticipant.LoginId=Login.LoginID
GROUP BY MessageThreadParticipant.MessageThreadId
)
ORDER BY Message.CreateDate DESC;
Advertisement
Answer
Does this do something like what you want?
SELECT
Login.LoginID,
Login.Username,
Message.MessageThreadID,
Message.MessageId,
Message.CreateDate,
Message.Body,
Sender.LoginID AS SenderLoginID,
Sender.Username AS SenderUsername,
MessageReadState.ReadDate AS RecipientReadDate
FROM
Login
INNER JOIN
MessageThreadParticipant
ON MessageThreadParticipant.LoginId = Login.LoginID
-- This gives all threads every LoginID has ever participated in
CROSS APPLY
(SELECT TOP 1 * FROM Message WHERE ThreadId = MessageThreadParticipant.MessageThreadId ORDER BY CreateDate DESC) AS Message
-- This gives the newest message for each of those threads.
-- The Login.LoginID could be either the Sender or Recipient
INNER JOIN
Login AS [Sender]
ON Sender.LoginID = Message.SenderLoginID
LEFT JOIN
MessageReadState
ON MessageReadState.MessageID = Message.MessageID
AND MessageReadState.LoginId <> Sender.LoginID
-- This gets the Sender's details, and tries to get whether the recipient read the message
-- It assumes the only MessageReadState entries are for the Sender and Recipient.
ORDER BY
Message.CreateDate DESC;