我需要帮助完成这项任务: 我在MsSql数据库中有一个表,我存储了用户间的消息。我需要一个查询来为每个用户对话选择最后一条消息(WhatApp类似于用户的会话列表)。
表格结构( x是消息ID,GUID,每条消息都是唯一的,txtMsg是短信):
| messageId | fromUserId | toUserId | Message | sentDate |
| x | 1 | 2 | txtMsg | 1.1.2016 1:00:00 |
| x | 1 | 2 | txtMsg | 1.1.2016 1:00:01 |
| x | 1 | 2 | txtMsg | 1.1.2016 1:00:02 |
| x | 2 | 1 | txtMsg | 1.1.2016 1:00:03 |
| x | 3 | 1 | txtMsg | 1.1.2016 1:00:04 |
| x | 4 | 1 | txtMsg | 1.1.2016 1:00:05 |
| x | 2 | 3 | txtMsg | 1.1.2016 1:00:06 |
| x | 2 | 4 | txtMsg | 1.1.2016 1:00:07 |
| x | 2 | 3 | txtMsg | 1.1.2016 1:00:08 |
| x | 1 | 5 | txtMsg | 1.1.2016 1:00:09 |
| x | 3 | 1 | txtMsg | 1.1.2016 1:00:10 |
| x | 2 | 4 | txtMsg | 1.1.2016 1:00:11 |
| x | 2 | 5 | txtMsg | 1.1.2016 1:00:12 |
| x | 1 | 2 | txtMsg | 1.1.2016 1:00:13 |
预期结果示例,对于id = 1的用户(sentDate是最新日期):
| x | 1 | 2 | txtMsg | 1.1.2016 1:00:13 |
| x | 3 | 1 | txtMsg | 1.1.2016 1:00:10 |
| x | 4 | 1 | txtMsg | 1.1.2016 1:00:05 |
| x | 1 | 5 | txtMsg | 1.1.2016 1:00:09 |
什么SQL查询会创建这样的结果?
谢谢!
稍后编辑: 我在这里添加了sqlfiddle示例:
答案 0 :(得分:5)
您可以使用案例逻辑row_nubmer
来获取最小和最大的用户ID:
select m.*
from (select m.*,
row_number() over (partition by (case when fromuserid < touserid then fromuserid else touserid end),
(case when fromuserid < touserid then touserid else fromuserid end)
order by sentDate desc
) as seqnum
from messages m
) m
where seqnum = 1;
编辑:
此SQL适用于SQL Fiddle:
select m.*
from (select m.*,
row_number() over (partition by (case when fromuser < touser then fromuser else touser end),
(case when fromuser < touser then touser else fromuser end)
order by createdAt desc
) as seqnum
from messages m
) m
where seqnum = 1;
答案 1 :(得分:1)
的内容如何
SELECT * FROM MessageData
WHERE messageID in
(SELECT messageID FROM
SELECT Max(sentDate), Max(messageID) messageID FROM
MessageData m1
INNER JOIN
MessageData m2
ON
m1.fromUserId = m2.toUserId
OR
m2.fromUserId = m1.toUserId
GROUP BY sentDate, MessageID
)
答案 2 :(得分:1)
与Gordon Linoff的回答非常相似。我刚为用户ID = 1添加了一个过滤器(from
或to
)。我将查询放在您的SQL Fiddle。
ROW_NUMBER
将所有行划分为对话,然后从最新开始(按createdAt
排序)为对话中的每一行分配序号。
WITH
CTE
AS
(
SELECT
M.Id
,M.fromUser
,M.toUser
,M.message
,M.createdAt
,ROW_NUMBER() OVER (
PARTITION BY
CASE WHEN M.fromUser < M.toUser THEN M.fromUser ELSE M.toUser END,
CASE WHEN M.fromUser > M.toUser THEN M.fromUser ELSE M.toUser END
ORDER BY M.createdAt DESC) AS rn
FROM Messages AS M
WHERE
M.fromUser = 1
OR M.toUser = 1
)
SELECT
CTE.Id
,CTE.fromUser
,CTE.toUser
,CTE.message
,CTE.createdAt
FROM CTE
WHERE rn = 1
ORDER BY fromUser, toUser;