聊天应用SQL查询完善需求
表结构
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 |
UserMessage表(会话消息记录)
| 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 |
期望输出
| 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 |
核心需求
- 在UserConversation表中筛选出JohnDoe(ID=1001)作为发送方或接收方的会话,返回会话对方的详细信息
- 统计每个会话中,JohnDoe作为接收方时未读消息(
MessageRead=0)的数量 - 按会话内最新消息的
CreateDate倒序排序
现有SQL代码
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
完善后的SQL查询
SELECT
uc.Id AS ConversationId,
-- 动态获取会话对方ID:当前用户是发送方则取接收方ID,反之取发送方ID
CASE
WHEN uc.SenderId = 1001 THEN uc.RecipientId
ELSE uc.SenderId
END AS UserId,
u.UserName,
up.Avatar AS UserAvatar,
-- 获取会话内最新消息时间
MAX(um.CreateDate) AS LatestDate,
-- 统计当前用户作为接收方的未读消息数
SUM(CASE
WHEN um.RecipientId = 1001 AND um.MessageRead = 0 THEN 1
ELSE 0
END) AS UnreadCount
FROM UserConversation uc
-- 关联消息表获取会话消息数据
LEFT JOIN UserMessage um ON uc.Id = um.ConversationId
-- 关联用户表获取对方信息
JOIN [User] u ON u.Id = CASE
WHEN uc.SenderId = 1001 THEN uc.RecipientId
ELSE uc.SenderId
END
-- 关联用户资料表获取头像
JOIN UserProfile up ON up.UserId = u.Id
WHERE uc.SenderId = 1001 OR uc.RecipientId = 1001
-- 按会话和用户信息分组,确保每个会话仅返回一条记录
GROUP BY uc.Id, u.Id, u.UserName, up.Avatar
-- 按最新消息时间倒序排序
ORDER BY LatestDate DESC;
关键优化说明
- 精准获取会话对方:用
CASE表达式判断当前用户在会话中的角色,避免无效的用户表关联 - 未读消息统计:通过
SUM+CASE组合,仅计数当前用户作为接收方且未读的消息 - 最新消息时间提取:用
MAX(um.CreateDate)直接获取会话内的最新消息时间 - 分组与排序:按会话ID和用户信息分组保证结果唯一性,最后按最新消息时间倒序排列
内容的提问来源于stack exchange,提问作者PixelPaul