获取每个用户对话的最新消息(含发送方与接收方信息)
发布时间 - 2026-01-06 00:00:00 点击率:次本文介绍如何通过 sql 子查询与多表连接,从 `messages` 表中高效获取每个用户对(from_id/to_id)的最新消息,并关联 `users` 表展示双方姓名、头像等完整会话摘要。
在构建即时通讯或私信模块时,一个常见需求是:为当前用户列出所有有过聊天记录的联系人,并显示每段对话中时间最新的那条消息(无论该消息是当前用户发出的还是收到的)。但原始代码仅能获取“当前用户作为发送方(from_id)”的最新消息,遗漏了对方主动发起的会话,且未正确处理双向对话关系。
核心问题在于:messages 表中每条记录仅代表单向交互(A→B 或 B→A),而“两人之间的最新消息”应视为一个无向会话单元。因此,需先标准化对话标识(例如按 LEAST(from_id, to_id) 和 GREATEST(from_id, to_id) 分组),再取每组中 created_at 最大的记录。
以下是推荐
的 Laravel 实现方案(兼容 MySQL 5.7+ / 8.0+):
✅ 正确 SQL 查询逻辑(支持双向会话)
SELECT
u1.id AS user_id,
u1.name AS user_name,
CONCAT('https://www.interwebs.co.in/puzzle/attach/', u1.avatar) AS user_image,
u2.id AS other_user_id,
u2.name AS other_user_name,
CONCAT('https://www.interwebs.co.in/puzzle/attach/', u2.avatar) AS other_user_image,
m.body AS message,
m.attachment,
m.seen AS seen_count,
m.created_at
FROM messages m
INNER JOIN (
-- 步骤1:为每对用户(无序)找出最新消息时间戳
SELECT
LEAST(from_id, to_id) AS user_a,
GREATEST(from_id, to_id) AS user_b,
MAX(created_at) AS latest_time
FROM messages
WHERE from_id = ? OR to_id = ?
GROUP BY user_a, user_b
) latest ON
LEAST(m.from_id, m.to_id) = latest.user_a
AND GREATEST(m.from_id, m.to_id) = latest.user_b
AND m.created_at = latest.latest_time
-- 步骤2:关联 users 表,动态识别当前用户与对方
INNER JOIN users u1 ON u1.id = CASE
WHEN m.from_id = ? THEN m.from_id ELSE m.to_id
END
INNER JOIN users u2 ON u2.id = CASE
WHEN m.from_id = ? THEN m.to_id ELSE m.from_id
END
ORDER BY m.created_at DESC;✅ Laravel 中安全执行(使用参数绑定防注入)
$userId = $request->user_id;
$sql = "SELECT
u1.id AS user_id,
u1.name AS user_name,
CONCAT('https://www.interwebs.co.in/puzzle/attach/', u1.avatar) AS user_image,
u2.id AS other_user_id,
u2.name AS other_user_name,
CONCAT('https://www.interwebs.co.in/puzzle/attach/', u2.avatar) AS other_user_image,
m.body AS message,
m.attachment,
m.seen AS seen_count,
m.created_at
FROM messages m
INNER JOIN (
SELECT
LEAST(from_id, to_id) AS user_a,
GREATEST(from_id, to_id) AS user_b,
MAX(created_at) AS latest_time
FROM messages
WHERE from_id = ? OR to_id = ?
GROUP BY user_a, user_b
) latest ON
LEAST(m.from_id, m.to_id) = latest.user_a
AND GREATEST(m.from_id, m.to_id) = latest.user_b
AND m.created_at = latest.latest_time
INNER JOIN users u1 ON u1.id = CASE
WHEN m.from_id = ? THEN m.from_id ELSE m.to_id
END
INNER JOIN users u2 ON u2.id = CASE
WHEN m.from_id = ? THEN m.to_id ELSE m.from_id
END
ORDER BY m.created_at DESC";
$chats = DB::select($sql, [$userId, $userId, $userId, $userId]);⚠️ 注意事项
- 索引优化:确保 messages 表上存在复合索引 INDEX(from_id, to_id, created_at) 和 INDEX(to_id, from_id, created_at),大幅提升分组与连接性能;
- 空值处理:若 avatar 字段可能为空,建议在 CONCAT 前用 COALESCE(u1.avatar, 'default.png') 防止拼接出无效 URL;
- 时间精度:若存在毫秒级重复 created_at,可追加 id 作为第二排序键(如 ORDER BY created_at DESC, id DESC)确保唯一性;
- Laravel 9+ 推荐替代方案:可封装为 Eloquent 查询作用域(Scope),或使用 DB::table()->fromSub() 构建子查询,提升可读性与可维护性。
该方案真正实现了「以用户为中心的会话聚合」——无论消息由谁发起、谁接收,只要两人之间存在交互,即归为同一会话并提取最新一条,完美匹配真实业务场景。
# mysql
# laravel
# 作用域
# sql
# 封装
# default
# table
# 两人
# 有过
# 仅代表
# 那条
# 私信
# 绑定
# 每条
# 仅能
# 即时通讯
# 为空
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
laravel怎么使用数据库工厂(Factory)生成带有关联模型的数据_laravel Factory生成关联数据方法
利用JavaScript实现拖拽改变元素大小
Laravel的路由模型绑定怎么用_Laravel Route Model Binding简化控制器逻辑
Linux虚拟化技术教程_KVMQEMU虚拟机安装与调优
如何快速完成中国万网建站详细流程?
如何用搬瓦工VPS快速搭建个人网站?
google浏览器怎么清理缓存_谷歌浏览器清除缓存加速详细步骤
高防服务器租用指南:配置选择与快速部署攻略
javascript事件捕获机制【深入分析IE和DOM中的事件模型】
,网页ppt怎么弄成自己的ppt?
Python高阶函数应用_函数作为参数说明【指导】
网站制作价目表怎么做,珍爱网婚介费用多少?
如何在建站宝盒中设置产品搜索功能?
成都品牌网站制作公司,成都营业执照年报网上怎么办理?
Laravel DB事务怎么使用_Laravel数据库事务回滚操作
Laravel如何使用withoutEvents方法临时禁用模型事件
免费制作统计图的网站有哪些,如何看待现如今年轻人买房难的情况?
免费网站制作appp,免费制作app哪个平台好?
东莞专业网站制作公司有哪些,东莞招聘网站哪个好?
长沙企业网站制作哪家好,长沙水业集团官方网站?
如何确保FTP站点访问权限与数据传输安全?
如何在Windows虚拟主机上快速搭建网站?
如何用AI一键生成爆款短视频文案?小红书AI文案写作指令【教程】
千库网官网入口推荐 千库网设计创意平台入口
JavaScript常见的五种数组去重的方式
javascript如何操作浏览器历史记录_怎样实现无刷新导航
Laravel怎么自定义错误页面_Laravel修改404和500页面模板
历史网站制作软件,华为如何找回被删除的网站?
Android实现代码画虚线边框背景效果
Laravel如何实现全文搜索功能?(Scout和Algolia示例)
新三国志曹操传主线渭水交兵攻略
Laravel如何使用Laravel Vite编译前端_Laravel10以上版本前端静态资源管理【教程】
Laravel Blade模板引擎语法_Laravel Blade布局继承用法
电商网站制作多少钱一个,电子商务公司的网站制作费用计入什么科目?
Laravel怎么进行数据库回滚_Laravel Migration数据库版本控制与回滚操作
香港服务器WordPress建站指南:SEO优化与高效部署策略
消息称 OpenAI 正研发的神秘硬件设备或为智能笔,富士康代工
html5的keygen标签为什么废弃_替代方案说明【解答】
制作ppt免费网站有哪些,有哪些比较好的ppt模板下载网站?
如何在云虚拟主机上快速搭建个人网站?
Laravel Vite是做什么的_Laravel前端资源打包工具Vite配置与使用
最好的网站制作公司,网购哪个网站口碑最好,推荐几个?谢谢?
如何确认建站备案号应放置的具体位置?
Linux系统命令中screen命令详解
如何在IIS服务器上快速部署高效网站?
JS中页面与页面之间超链接跳转中文乱码问题的解决办法
Python企业级消息系统教程_KafkaRabbitMQ高并发应用
如何用PHP快速搭建高效网站?分步指南
Laravel如何使用Spatie Media Library_Laravel图片上传管理与缩略图生成【步骤】
如何在腾讯云服务器快速搭建个人网站?
上一篇:伪命令req功能的详细介绍
上一篇:伪命令req功能的详细介绍

