Laravel 10中按日期分组去重需据业务目标选择方案:①取每天最新记录用子查询或窗口函数;②统计每日去重数量用COUNT(DISTINCT);③真去重同天完全重复行用MIN(id)子查询。

在 Laravel 10 中按日期分组查询并去重,关键不是“单纯去重”,而是明确业务目标:你是想 按日期聚合数据(如每天取一条最新记录),还是 过滤掉同一天内完全重复的行?两者写法不同,下面分场景说明。
场景一:按日期(如 day)分组,取每组中某字段最新/最全的一条
这是最常见的需求,比如“查每天最后创建的一条订单”。Laravel 原生不支持直接 `GROUP BY` + `SELECT *`(MySQL 5.7+ strict mode 下会报错),需用子查询或窗口函数。
推荐用子查询(兼容性好):
- 先查出每天最大的 id(或 created_at)
- 再关联原表获取完整记录
示例代码(查每天最新一条用户登录记录):
$latestLogins = DB::table('user_logins as ul1')
->select('ul1.*')
->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('user_logins as ul2')
->whereColumn('ul2.user_id', 'ul1.user_id')
->whereDate('ul2.created_at', DB::raw('DATE(ul1.created_at)'))
->havingRaw('MAX(ul2.created_at) = ul1.created_at');
})
->get();
更简洁可靠的做法是用 自连接 + 窗口函数(Laravel 10 支持 raw 表达式)(MySQL 8.0+/PostgreSQL):
$results = DB::select("
SELECT * FROM (
SELECT *,
ROW_NUMBER() OVER (
PARTITION BY DATE(created_at)
ORDER BY created_at DESC
) AS rn
FROM user_logins
) ranked
WHERE rn = 1
");
场景二:按日期分组后统计去重数量(如每天多少个不同用户)
这属于聚合统计,直接用 `COUNT(DISTINCT ...)` 即可:
$stats = DB::table('user_logins')
->select(
DB::raw('DATE(created_at) as date'),
DB::raw('COUNT(DISTINCT user_id) as unique_users')
)
->groupBy(DB::raw('DATE(created_at)'))
->orderBy('date')
->get();
结果形如:[{"date":"2024-04-01","unique_users":24}, ...]
场景三:查询时忽略同一天内完全相同的记录(真去重)
如果表中存在多条 created_at 同天且所有字段都一样的冗余数据,可用:
-
DISTINCT配合日期截取(适合字段不多、能确定“完全相同”的情况) - 或先用
DATE(created_at)分组,再用MIN(id)取唯一主键,再IN查询
示例(取每天任意一条,确保不重复):
$uniqueByDay = DB::table('user_logins')
->whereIn('id', function ($query) {
$query->select(DB::raw('MIN(id)'))
->from('user_logins')
->groupBy(DB::raw('DATE(created_at)'));
})
->get();
额外提醒
• 使用 DATE(created_at) 时,确保 created_at 是 datetime/timestamp 类型,且有索引(可建函数索引或生成列索引提升性能)
• Laravel 的 groupBy() 必须包含 select() 中所有非聚合字段,否则在 strict 模式下报错
• 若用 Eloquent 模型,可在模型中定义访问器或使用 toDateString() 配合集合处理(小数据量可行,大数据量务必在数据库层处理)


















