掌握Laravel查询:Distinct与GroupBy在多表联接中的正确用法

DDD

DDD

2025-09-12

486人浏览

原创

掌握Laravel查询:Distinct与GroupBy在多表联接中的正确用法

本文深入探讨了在Laravel中进行多表联接查询时,如何精确地获取期望的唯一ID或唯一记录。针对distinct()方法在无明确select()时的默认行为,文章提供了两种核心解决方案:通过select()与distinct()组合来获取特定列的唯一值,以及利用groupBy()方法获取每组的完整唯一记录,并详细阐述了它们的应用场景与注意事项,旨在帮助开发者避免常见的查询陷阱。

laravel的数据库查询构建器中,当执行多表联接(join)操作并尝试获取特定列的唯一值时,开发者常会遇到一个常见问题:即使使用了distinct()方法,结果集中的id可能并非预期的目标表id,而是其他联接表的id。这通常是由于distinct()方法的默认行为以及查询构建器隐式选择所有列所导致的。

理解distinct()的默认行为

当您在不明确指定select()的情况下使用distinct()时,Laravel的查询构建器会默认选择所有联接表中的所有列(SELECT *)。在这种情况下,distinct()会作用于整个结果行,这意味着只有当一行中的所有列值都完全相同时,该行才会被视为重复并被排除。如果联接的表中存在其他列的值不同,即使目标ID相同,整行也会被认为是唯一的,从而无法达到获取目标ID唯一值的目的。

例如,原始查询如下:

$objectives = DB::table('objectives')
    ->join('users', 'objectives.assigned_id', '=', 'users.id')
    ->join('media', 'objectives.training_document_id', '=', 'media.model_id')
    ->where('objectives.assigned_id', '=', $assigned_id)
    ->where('media.model_type', '=', 'App\Models\TrainingDoc')
    ->distinct('objectives.id') // 这里的distinct('objectives.id')实际上不会生效
    ->get();

在这个例子中,distinct('objectives.id')并不能如预期般只返回objectives.id的唯一值。因为distinct()如果没有明确的select()语句,它会尝试对所有列进行去重,而传递给distinct()的参数通常会被忽略或误解。

解决方案一:明确指定select()并结合distinct()

要正确获取特定列的唯一值,最直接有效的方法是显式地使用select()方法指定您需要去重的那一列,然后再调用distinct()方法。这样,distinct()将仅作用于您明确选择的列,从而返回该列的唯一值集合。

$objectives = DB::table('objectives')
    ->select('objectives.id') // 明确选择 objectives.id
    ->distinct()             // 对选择的 objectives.id 进行去重
    ->join('users', 'objectives.assigned_id', '=', 'users.id')
    ->join('media', 'objectives.training_document_id', '=', 'media.model_id')
    ->where('objectives.assigned_id', '=', $assigned_id)
    ->where('media.model_type', '=', 'App\Models\TrainingDoc')
    ->get();

通过这种方式,get()方法将返回一个包含唯一objectives.id值的集合。每个集合元素将是一个对象,其中只包含id属性。

度加AI
度加AI

度加AI官网入口,百度官方 AIGC 创作平台,支持 AI 成片、AI 生文、数字人、声音克隆、配音字幕与智能剪辑等在线创作能力。

下载

注意事项:

  • 如果您需要获取多个列的唯一组合,可以在select()中指定多个列,例如 ->select('objectives.id', 'objectives.name')->distinct()。此时,distinct()将对id和name的组合进行去重。
  • 此方法适用于您只需要获取唯一ID列表,而不需要每条记录的完整详细信息的情况。

解决方案二:使用groupBy()获取唯一记录

如果您不仅需要获取唯一的objectives.id,而且希望为每个唯一的objectives.id获取一条完整的记录(例如,该objective的所有相关字段),那么groupBy()方法是一个更合适的选择。groupBy()会将结果集按照指定的列进行分组,并通常返回每个分组的第一条记录(具体行为可能因数据库系统和SQL模式而异,但在Laravel的常见使用场景下,它能有效地达到此目的)。

$objectives = DB::table('objectives')
    ->join('users', 'objectives.assigned_id', '=', 'users.id')
    ->join('media', 'objectives.training_document_id', '=', 'media.model_id')
    ->where('objectives.assigned_id', '=', $assigned_id)
    ->where('media.model_type', '=', 'App\Models\TrainingDoc')
    ->groupBy('objectives.id') // 按照 objectives.id 分组
    ->get();

使用groupBy('objectives.id')后,get()方法将返回一个集合,其中每个元素代表一个唯一的objectives.id所对应的记录。这些记录将包含所有联接表中的列(除非您使用select()明确指定了要返回的列)。

注意事项:

  • 当使用groupBy()时,如果同时选择非分组列且不使用聚合函数(如COUNT(), SUM(), MAX()等),某些数据库(如MySQL在ONLY_FULL_GROUP_BY模式下)可能会报错。在Laravel中,默认情况下通常不会遇到此问题,因为它会选择每个组的第一条记录。
  • 如果您需要对分组后的数据进行聚合计算,可以在select()中添加聚合函数,例如 ->select('objectives.id', DB::raw('COUNT(users.id) as user_count'))。
  • 此方法适用于您需要基于某个ID获取唯一记录的完整数据,或者需要对分组数据进行统计分析的场景。

总结与选择建议

特性/方法 select('column')->distinct() groupBy('column')
目的 获取指定列的唯一值列表 获取每个唯一分组的完整记录(或用于聚合统计)。
返回内容 仅包含指定列的唯一值(如 [{id: 1}, {id: 2}])。 包含所有选择列的完整记录(如 [{id: 1, name: 'A', ...}, {id: 2, name: 'B', ...}])。
适用场景 仅关心唯一ID本身,例如用于下拉列表选项、ID集合校验等。 需要每条唯一记录的完整数据,或需要对分组数据进行聚合计算。
性能考量 通常更高效,因为只选择和处理少量数据。 可能涉及更多的数据处理,尤其是在选择所有列时。

在实际开发中,根据您的具体需求选择合适的方法至关重要。如果仅仅需要一个唯一ID的列表,select()->distinct()是更简洁高效的选择。而如果需要基于唯一ID获取完整的记录信息,或者进行更复杂的数据聚合,那么groupBy()将是您的首选。理解这两种方法的内在机制和适用场景,将帮助您更精确、高效地构建Laravel数据库查询。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
laravel组件介绍
laravel组件介绍

laravel 提供了丰富的组件,包括身份验证、模板引擎、缓存、命令行工具、数据库交互、对象关系映射器、事件处理、文件操作、电子邮件发送、队列管理和数据验证。想了解更多laravel的相关内容,可以阅读本专题下面的文章。

2024.04.09

671

10

laravel中间件介绍
laravel中间件介绍

laravel 中间件分为五种类型:全局、路由、组、终止和自定。想了解更多laravel中间件的相关内容,可以阅读本专题下面的文章。

2024.04.09

626

9

laravel使用的设计模式有哪些
laravel使用的设计模式有哪些

laravel使用的设计模式有:1、单例模式;2、工厂方法模式;3、建造者模式;4、适配器模式;5、装饰器模式;6、策略模式;7、观察者模式。想了解更多laravel的相关内容,可以阅读本专题下面的文章。

2024.04.09

1108

10

thinkphp和laravel哪个简单
thinkphp和laravel哪个简单

对于初学者来说,laravel 的入门门槛较低,更易上手,原因包括:1. 更简单的安装和配置;2. 丰富的文档和社区支持;3. 简洁易懂的语法和 api;4. 平缓的学习曲线。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.10

1523

7

laravel入门教程
laravel入门教程

本专题整合了laravel入门教程,想了解更多详细内容,请阅读专题下面的文章。

2025.08.05

1879

22

laravel实战教程
laravel实战教程

本专题整合了laravel实战教程,阅读专题下面的文章了解更多详细内容。

2025.08.05

1202

13

laravel面试题
laravel面试题

本专题整合了laravel面试题相关内容,阅读专题下面的文章了解更多详细内容。

2025.08.05

2642

7

PHP高性能API设计与Laravel服务架构实践
PHP高性能API设计与Laravel服务架构实践

本专题围绕 PHP 在现代 Web 后端开发中的高性能实践展开,重点讲解基于 Laravel 框架构建可扩展 API 服务的核心方法。内容涵盖路由与中间件机制、服务容器与依赖注入、接口版本管理、缓存策略设计以及队列异步处理方案。同时结合高并发场景,深入分析性能瓶颈定位与优化思路,帮助开发者构建稳定、高效、易维护的 PHP 后端服务体系。

2026.03.04

1087

29

Laravel 框架安装指南
Laravel 框架安装指南

本指南详解 Laravel 框架安装全流程,涵盖 PHP 8.1+ 环境配置、Composer 依赖管理工具安装及国内镜像源优化。重点演示使用 composer create-project 命令创建 Laravel 10/11 项目,解决常见安装错误与依赖冲突。从环境搭建到项目初始化,助您快速完成 Laravel 开发环境部署,为后续 Web 应用开发奠定基础。适合 PHP 初学者与框架迁移开发者参考。

2026.04.09

91

6

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL vs MySQL
PostgreSQL vs MySQL

共1课时 | 122人学习

使用phpenv集成环境安装极致CMS
使用phpenv集成环境安装极致CMS

共2课时 | 221人学习

phpEnv手册
phpEnv手册

共0课时 | 0人学习