I'm really struggling to understand how to write a query. There are two main tables for a chat feature. The UserConversation
table holds the sender and recipient id's for a two way chat. The UserMessage
table holds the corresponding messages. The User
and UserProfile
tables are needed just to pull some extra details from. Here is the table structure:
UserConversation
Id | SenderId | SenderDeleteDate | RecipientId | RecipientDeleteDate | CreateDate |
---|---|---|---|---|---|
1 | 1002 | NULL | 1001 | NULL | 2023-12-23 14:14:13.1152723 +07:00 |
2 | 1001 | NULL | 1003 | NULL | 2023-12-23 14:15:20.1264302 +07:00 |
3 | 1001 | NULL | 1004 | NULL | 2023-12-23 14:16:57.4302621 +07:00 |
User
Id | UserName |
---|---|
1001 | JohnDoe |
1002 | BenDover |
1003 | JakeSmith |
1004 | KrisKringle |
UserProfile
UserId | Avatar |
---|---|
1001 | avatar/image/1001.jpg |
1002 | avatar/image/1002.jpg |
1003 | avatar/image/1003.jpg |
1004 | avatar/image/1004.jpg |
UserMesage
ConversationId | SenderId | RecipientId | MessageRead | Message | CreateDate |
---|---|---|---|---|---|
1 | 1002 | 1001 | 0 | Hello | 2023-12-22 13:00:00 |
1 | 1001 | 1002 | 0 | Hi there | 2023-12-22 13:30:00 |
2 | 1001 | 1003 | 1 | Merry Christmas | 2023-12-22 14:00:00 |
2 | 1003 | 1001 | 1 | Same to you | 2023-12-22 14:30:00 |
3 | 1001 | 1004 | 1 | Grab some beers? | 2023-12-22 15:00:00 |
3 | 1004 | 1001 | 0 | Sure | 2023-12-22 15:30:00 |
I'm trying to achieve the following output:
ConversationId | UserId | UserName | UserAvatar | LatestDate | UnreadCount |
---|---|---|---|---|---|
3 | 1004 | KrisKringle | avatar/image/1004.jpg | 2023-12-22 15:30:00 | 1 |
2 | 1003 | JakeSmith | avatar/image/1003.jpg | 2023-12-22 14:30:00 | 0 |
1 | 1002 | BenDover | avatar/image/1002.jpg | 2023-12-22 13:30:00 | 1 |
A few notes:
UserConversation
table for occurrences where JohnDoe
is the SenderId
or RecipientId
, but I want to return the user details of the other user.MessageRead
column on the UserMessages
table for each conversation, but only where the searched user (JohnDoe
) is the message recipient.CreateDate
I haven't gotten very far, here is what I have so far.
select
uc.Id as Id,
us.Id as UserId,
us.UserName as Username,
ups.AvatarImage as UserAvatar
from UserConversation uc
join UserMessage um on uc.Id = um.ConversationId
join [User] us on uc.SenderId = us.Id
join [User] ur on uc.RecipientId = ur.Id
join UserProfile ups on us.Id = ups.UserId
join UserProfile upr on ur.Id = upr.UserId
where uc.SenderId = 1001 or uc.RecipientId = 1001
Since you want the rows with JohnDoe as either sender or recipient along with the other participant you should join User and UserProfile tables twice (once for sender and other for recipient). Having that done you can do aggregations and grouping and some case expressions (or Decode() function or anything else similar) to take the right data for your expected result. I don't know T-SQL but it's syntax is similar enough to Oracle's SQL. I'm sure you could adopt the code below and transcript it to T-SQL.
WITH -- S a m p l e D a t a :
UserConversation (Id, SenderId, SenderDeleteDate, RecipientId, RecipientDeleteDate, CreateDate) AS
( Select 1, 1002, NULL, 1001, NULL, TIMESTAMP '2023-12-23 14:14:13.1152723 +07:00' From Dual Union All
Select 2, 1001, NULL, 1003, NULL, TIMESTAMP '2023-12-23 14:15:20.1264302 +07:00' From Dual Union All
Select 3, 1001, NULL, 1004, NULL, TIMESTAMP '2023-12-23 14:16:57.4302621 +07:00' From Dual
),
Users (Id, UserName) AS
( Select 1001, 'JohnDoe' From Dual Union All
Select 1002, 'BenDover' From Dual Union All
Select 1003, 'JakeSmith' From Dual Union All
Select 1004, 'KrisKringle' From Dual
),
UserProfile (UserId, Avatar) AS
( Select 1001, 'avatar/image/1001.jpg' From Dual Union All
Select 1002, 'avatar/image/1002.jpg' From Dual Union All
Select 1003, 'avatar/image/1003.jpg' From Dual Union All
Select 1004, 'avatar/image/1004.jpg' From Dual
),
UserMessage (ConversationId, SenderId, RecipientId, MessageRead, Message, CreateDate) AS
( Select 1, 1002, 1001, 0, 'Hello', To_Date('2023-12-22 13:00:00', 'yyyy-mm-dd hh24:mi:ss') From Dual Union All
Select 1, 1001, 1002, 0, 'Hi there', To_Date('2023-12-22 13:30:00', 'yyyy-mm-dd hh24:mi:ss') From Dual Union All
Select 2, 1001, 1003, 1, 'Merry Christmas', To_Date('2023-12-22 14:00:00', 'yyyy-mm-dd hh24:mi:ss') From Dual Union All
Select 2, 1003, 1001, 1, 'Same to you', To_Date('2023-12-22 14:30:00', 'yyyy-mm-dd hh24:mi:ss') From Dual Union All
Select 3, 1001, 1004, 1, 'Grab some beers?', To_Date('2023-12-22 15:00:00', 'yyyy-mm-dd hh24:mi:ss') From Dual Union All
Select 3, 1004, 1001, 0, 'Sure', To_Date('2023-12-22 15:30:00', 'yyyy-mm-dd hh24:mi:ss') From Dual
)
Oracle:
-- M a i n S Q L :
Select c.ID "CONVERSATION_ID",
Max(Case When usnd.USERNAME = 'JohnDoe' Then urcp.ID Else usnd.ID End) "USER_ID",
Max(Case When usnd.USERNAME = 'JohnDoe' Then urcp.USERNAME Else usnd.USERNAME End) "USER_NAME",
Max(Case When usnd.USERNAME = 'JohnDoe' Then uprcp.AVATAR Else upsnd.AVATAR End) "USER_AVATAR",
To_Char(Max(um.CREATEDATE), 'yyyy-mm-dd hh24:mi:ss') "LATEST_DATE",
Count(Case When urcp.USERNAME = 'JohnDoe' And um.MessageRead = 0 Then 1 End) "UNREAD_COUNT"
From UserMessage um
Inner Join UserConversation c ON(um.ConversationId = c.ID)
Inner Join Users usnd ON(usnd.ID = um.SENDERID)
Inner Join Users urcp ON(urcp.ID = um.RECIPIENTID)
Inner Join UserProfile upsnd ON(upsnd.USERID = c.SENDERID)
Inner Join UserProfile uprcp ON(uprcp.USERID = c.RECIPIENTID)
Where 'JohnDoe' IN(usnd.USERNAME, urcp.USERNAME)
Group By c.ID
Order By c.ID Desc
/* R e s u l t :
CONVERSATION_ID USER_ID USER_NAME USER_AVATAR LATEST_DATE UNREAD_COUNT
--------------- ---------- ----------- --------------------- ------------------- ------------
3 1004 KrisKringle avatar/image/1004.jpg 2023-12-22 15:30:00 1
2 1003 JakeSmith avatar/image/1003.jpg 2023-12-22 14:30:00 0
1 1002 BenDover avatar/image/1002.jpg 2023-12-22 13:30:00 1 */