Laravel多表关联查询后如何合并重复客户记录展示?
解决方案:合并同一客户的联系方式记录
当然可以实现,下面提供两种常用的解决思路:
方法一:使用查询构造器结合聚合函数(适合直接用DB类的场景)
利用数据库的聚合函数(如MySQL的GROUP_CONCAT)将同一客户的多条电话、邮箱合并为字符串,同时通过GROUP BY按客户分组,避免重复记录。另外需要修正原代码中OR条件的逻辑问题(原写法会导致搜索条件脱离主表关联,引发错误)。
修改后的代码如下:
public function customersList(Request $request) { $query = DB::table('customers') ->leftJoin('phones', 'customers.id', '=', 'phones.customer_id') ->leftJoin('emails', 'customers.id', '=', 'emails.customer_id') ->select( 'customers.id', 'customers.name', DB::raw('GROUP_CONCAT(DISTINCT phones.phone SEPARATOR ", ") as phones'), DB::raw('GROUP_CONCAT(DISTINCT emails.email SEPARATOR ", ") as emails') ) ->groupBy('customers.id', 'customers.name'); if (!empty($request->value)) { $searchValue = '%' . $request->value . '%'; $query->where(function ($q) use ($searchValue) { $q->where('customers.name', 'like', $searchValue) ->orWhere('emails.email', 'like', $searchValue) ->orWhere('phones.phone', 'like', $searchValue); }); } $info = $query->get(); // 可选:将逗号分隔的字符串转成数组,方便前端处理 // $info = $info->map(function($item) { // $item->phones = explode(', ', $item->phones) ?: []; // $item->emails = explode(', ', $item->emails) ?: []; // return $item; // }); return $info; }
说明:
- 改用
leftJoin确保即使客户没有电话或邮箱也能被查询到 GROUP_CONCAT的DISTINCT参数避免重复的联系方式- 搜索条件用闭包包裹,保证
OR逻辑只作用于搜索字段,不破坏表关联的条件
方法二:使用Eloquent关联(更符合Laravel的ORM设计)
如果已经定义了Eloquent模型,这种方式更优雅,通过定义一对多关联,然后在查询时预加载关联数据,最后通过集合处理合并:
- 先定义模型关联:
// Customer.php 模型 class Customer extends Model { public function phones() { return $this->hasMany(Phone::class); } public function emails() { return $this->hasMany(Email::class); } }
- 修改控制器方法:
public function customersList(Request $request) { $query = Customer::with(['phones', 'emails']); if (!empty($request->value)) { $searchValue = '%' . $request->value . '%'; $query->where(function ($q) use ($searchValue) { $q->where('name', 'like', $searchValue) ->orWhereHas('phones', function ($q2) use ($searchValue) { $q2->where('phone', 'like', $searchValue); }) ->orWhereHas('emails', function ($q2) use ($searchValue) { $q2->where('email', 'like', $searchValue); }); }); } $info = $query->get()->map(function($customer) { return [ 'id' => $customer->id, 'name' => $customer->name, 'phones' => $customer->phones->pluck('phone')->toArray(), 'emails' => $customer->emails->pluck('email')->toArray(), ]; }); return $info; }
说明:
with(['phones', 'emails'])预加载关联数据,避免N+1查询问题whereHas用于搜索关联表中的字段- 通过集合的
map和pluck方法,将关联的电话、邮箱整理成数组,合并到客户记录中
内容的提问来源于stack exchange,提问作者Solutions
相关产品推荐
相关产品推荐

