SQL Server 2017能否对两列分组?如何获取与UserID1聊天用户的最后消息
问题1解答:SQL Server 2017中能否对两列应用GROUP BY?
完全可以!GROUP BY子句支持同时指定多个列,这是SQL的标准特性,SQL Server 2017当然也支持。当你对多列使用GROUP BY时,数据库会将所有指定列的组合值相同的行归为一组,之后就能对每组使用聚合函数(比如COUNT、MAX、SUM等)做统计计算。举个简单的示例:
SELECT MessageCreatorUserID, MessageRecieverUserID, COUNT(*) AS MessageCount FROM Messages GROUP BY MessageCreatorUserID, MessageRecieverUserID;
这个查询会按发送者和接收者的组合分组,统计每对用户之间的消息总数。
问题2解答:获取与UserID 1聊天的用户的最后一条消息
针对你给出的消息表结构和数据,我们需要先定位所有和UserID 1有过互动的用户(不管1是消息发送方还是接收方),再找出每个用户与1之间的最后一条消息。下面提供两种实现方式,其中包含你要求的GROUP BY用法:
方法1:基于GROUP BY的分步查询
步骤1:整理聊天伙伴关系
先筛选出所有和1相关的消息,并把聊天伙伴的ID统一提取到单独列中:
SELECT CASE WHEN MessageCreatorUserID = 1 THEN MessageRecieverUserID ELSE MessageCreatorUserID END AS ChatPartnerID, MessageID, Message, CreatedAt, MessageCreatorUserID, MessageRecieverUserID FROM Messages WHERE MessageCreatorUserID = 1 OR MessageRecieverUserID = 1;
步骤2:用GROUP BY获取每个伙伴的最后消息时间
分组每个聊天伙伴,拿到他们和1聊天的最晚消息时间:
SELECT ChatPartnerID, MAX(CreatedAt) AS LastMessageTime FROM ( SELECT CASE WHEN MessageCreatorUserID = 1 THEN MessageRecieverUserID ELSE MessageCreatorUserID END AS ChatPartnerID, CreatedAt FROM Messages WHERE MessageCreatorUserID = 1 OR MessageRecieverUserID = 1 ) AS PartnerMessages GROUP BY ChatPartnerID;
步骤3:关联原表获取完整消息详情
将上面的结果和原表关联,就能拿到每个聊天伙伴的最后一条消息:
SELECT m.MessageID, m.Message, m.MessageCreatorUserID, m.MessageRecieverUserID, m.CreatedAt, CASE WHEN m.MessageCreatorUserID = 1 THEN m.MessageRecieverUserID ELSE m.MessageCreatorUserID END AS ChatPartnerID FROM Messages m INNER JOIN ( SELECT CASE WHEN MessageCreatorUserID = 1 THEN MessageRecieverUserID ELSE MessageCreatorUserID END AS ChatPartnerID, MAX(CreatedAt) AS LastMessageTime FROM Messages WHERE MessageCreatorUserID = 1 OR MessageRecieverUserID = 1 GROUP BY CASE WHEN MessageCreatorUserID = 1 THEN MessageRecieverUserID ELSE MessageCreatorUserID END ) AS LastMessages ON (CASE WHEN m.MessageCreatorUserID = 1 THEN m.MessageRecieverUserID ELSE m.MessageCreatorUserID END) = LastMessages.ChatPartnerID AND m.CreatedAt = LastMessages.LastMessageTime ORDER BY m.CreatedAt DESC;
方法2:用窗口函数简化实现(更高效)
如果不想嵌套多层子查询,也可以用ROW_NUMBER()窗口函数实现,写法更简洁:
SELECT * FROM ( SELECT MessageID, Message, MessageCreatorUserID, MessageRecieverUserID, CreatedAt, CASE WHEN MessageCreatorUserID = 1 THEN MessageRecieverUserID ELSE MessageCreatorUserID END AS ChatPartnerID, ROW_NUMBER() OVER (PARTITION BY CASE WHEN MessageCreatorUserID = 1 THEN MessageRecieverUserID ELSE MessageCreatorUserID END ORDER BY CreatedAt DESC) AS RowNum FROM Messages WHERE MessageCreatorUserID = 1 OR MessageRecieverUserID = 1 ) AS RankedMessages WHERE RowNum = 1 ORDER BY CreatedAt DESC;
这个查询会给每个聊天伙伴的消息按时间倒序排名,取排名为1的那条(也就是最后一条消息)。
针对你的示例数据,运行上述查询会得到以下结果:
- 聊天伙伴4的最后一条消息是ID1的
HI - 聊天伙伴3的最后一条消息是ID5的
hii - 聊天伙伴2的最后一条消息是ID4的
Thanks
内容的提问来源于stack exchange,提问作者Amandeep Singh
相关产品推荐
相关产品推荐

