
本文解析 laravel eloquent 中 distinct() 方法在配合 get() 与 count() 时的行为差异,阐明其底层 sql 原理,并提供正确实现去重查询(尤其是按指定字段去重)的多种方案。
本文解析 laravel eloquent 中 distinct() 方法在配合 get() 与 count() 时的行为差异,阐明其底层 sql 原理,并提供正确实现去重查询(尤其是按指定字段去重)的多种方案。
在 Laravel 中,distinct() 方法的作用是生成 SELECT DISTINCT SQL 语句,但它不支持接收字段名参数(如 distinct('product_id')),该写法在 Laravel 10+ 中已被废弃,且在早期版本中也仅作无效忽略——Eloquent 会直接忽略传入的字段,仍执行全行去重(即 SELECT DISTINCT *)。因此,你遇到的问题本质如下:
- ✅ ->distinct()->count('product_id') 实际等价于 COUNT(DISTINCT product_id)(Laravel 自动优化),返回去重后的数量(如 2);
- ❌ ->distinct('product_id')->get() 不会按 product_id 去重,而是执行 SELECT DISTINCT * FROM ...,返回所有不重复的完整记录行,并非按单字段聚合去重;
- ⚠️ 你答案中写的 count('producr_id) 存在拼写错误(应为 product_id),且语法虽可运行,但推荐显式使用 countDistinct() 提升可读性与健壮性。
正确实现“按 product_id 去重获取数据”的方法
✅ 方案 1:使用 select('product_id')->distinct()->get()(推荐)
仅查询目标字段并去重,返回集合:
$customers = OrderItem::whereIn('order_id', $customers_id)
->select('product_id')
->distinct()
->get(); // 返回 Collection of ['product_id' => 1], ['product_id' => 5]...
// 若只需纯数组值,链式调用 pluck:
$productIds = OrderItem::whereIn('order_id', $customers_id)
->pluck('product_id')
->unique() // Eloquent 集合级去重(内存中),适用于小数据量
->values()
->all();✅ 方案 2:使用原生 GROUP BY(更高效,推荐大数据量场景)
$customers = OrderItem::whereIn('order_id', $customers_id)
->select('product_id')
->groupBy('product_id')
->get();✅ 方案 3:统计去重数量(最常用)
// 推荐写法:语义清晰,兼容性好
$count = OrderItem::whereIn('order_id', $customers_id)
->countDistinct('product_id'); // Laravel 9.28+ 支持
// 兼容旧版 Laravel(<9.28):
$count = OrderItem::whereIn('order_id', $customers_id)
->selectRaw('COUNT(DISTINCT product_id)')
->value('COUNT(DISTINCT product_id)');注意事项
- distinct() 必须放在 select() 之后、get()/count() 之前才生效;
- distinct('field') 是无效用法,切勿依赖;
- get() 返回的是模型集合(含全部字段),若只需单字段去重结果,请务必配合 select() 使用;
- 数据量大时,优先使用数据库层 GROUP BY 或 COUNT(DISTINCT ...),避免 PHP 层 unique() 导致内存压力。
掌握 distinct() 的真实行为与替代方案,能帮你写出更高效、可维护的 Laravel 查询逻辑。


















