如何在Laravel中用查询构造器实现指定去重SQL查询?
问题解决:Laravel 实现指定SQL查询及重复数据问题处理
1. 修正查询构造器的拼写错误
你写的查询构造器里有个明显的拼写错误:orderBy('aerucul') 应该是 orderBy('articul'),修正后的标准构造器写法如下:
$products = Product::select('id', 'name', 'articul') ->where('category_id', 40) ->distinct() ->orderBy('articul') ->get();
2. 对应的模型方法实现
可以在 Product 模型中封装一个静态方法,方便复用这个查询逻辑:
namespace App\Models; use Illuminate\Database\Eloquent\Model; class Product extends Model { // 若模型名与表名一致,可省略$table定义 protected $table = 'products'; public static function getDistinctProductsByCategory($categoryId) { return self::select('id', 'name', 'articul') ->where('category_id', $categoryId) ->distinct() ->orderBy('articul') ->get(); } }
调用示例:
$products = Product::getDistinctProductsByCategory(40);
3. 重复数据问题的核心原因
你提到用 DB::select 直接执行原始SQL也出现重复,说明问题不是Laravel语法错误,而是对 DISTINCT 的逻辑理解偏差:
SELECT DISTINCT id, name, articul是基于三个字段的组合去重,只要其中任意一个字段值不同,就会被视为独立记录保留。- 由于
id是表的主键(默认自增唯一),即使name和articul完全相同,只要id不同,DISTINCT就不会合并这些记录。
如果你的真实需求是按articul字段去重(忽略id差异),应该改用groupBy,而非DISTINCT,具体写法分两种情况:
方式一:兼容严格SQL模式(推荐)
用ANY_VALUE函数包裹非分组字段,避免ONLY_FULL_GROUP_BY报错:
$products = Product::select( 'articul', \DB::raw('ANY_VALUE(id) as id'), \DB::raw('ANY_VALUE(name) as name') ) ->where('category_id', 40) ->groupBy('articul') ->orderBy('articul') ->get();
方式二:关闭MySQL严格模式
修改config/database.php中mysql配置项的strict为false后,可直接写:
$products = Product::select('id', 'name', 'articul') ->where('category_id', 40) ->groupBy('articul') ->orderBy('articul') ->get();
4. 验证原始SQL的实际效果
你可以在phpMyAdmin中重新执行原始SQL,仔细查看结果中的id字段,会发现即使name和articul相同,id不同的记录依然会被保留——之前误以为原始SQL无重复,其实是忽略了id的唯一性导致的"假重复"。
内容的提问来源于stack exchange,提问作者Andrey Yanok
相关产品推荐
相关产品推荐

