Laravel跨库whereIn结合leftJoin关联查询时数据异常问题
问题根因
你遇到的两个问题是SQL联表查询在一对多场景下的固有表现,不是框架bug:原生leftJoin执行时,主表(posts)每匹配到一条关联从表(comments)的记录,就会单独生成一行返回结果,所以如果某篇文章有3条评论,结果里就会出现3条该文章的重复行,每行只附带1条对应的评论数据。
另外你写的联表条件存在笔误:leftJoin第二个参数传入的是post.id_post,主表实际表名是posts,少了末尾的s,即使解决重复问题,这个笔误也会触发字段不存在的SQL报错。
解决方案
有两种成熟的实现方式,按需选择即可。
方案1:Eloquent关联预加载(推荐)
这是Laravel处理一对多关联的标准写法,框架会自动组装「文章挂载评论数组」的嵌套结构,不会产生重复数据。
首先为跨库表定义对应模型,配置关联关系:
// 文章模型 app/Models/Post.php namespace App\Models; use Illuminate\Database\Eloquent\Model; class Post extends Model { protected $connection = 'mysqlDatabase2'; // 指定跨库连接 protected $table = 'posts'; protected $primaryKey = 'id_post'; // 自定义主键 // 定义一对多评论关联 public function comments() { return $this->hasMany(Comment::class, 'id_post', 'id_post'); } }
// 评论模型 app/Models/Comment.php namespace App\Models; use Illuminate\Database\Eloquent\Model; class Comment extends Model { protected $connection = 'mysqlDatabase2'; protected $table = 'comments'; // 评论表主键按实际字段名调整即可 protected $primaryKey = 'id_comment'; }
查询代码直接调用预加载方法:
$ids = [1, 2, 4, 7]; $data = Post::whereIn('id_post', $ids) ->with('comments') // 预加载关联评论,自动解决重复和结构问题 ->get();
最终返回的每条文章记录会自带comments属性,值为该文章下所有评论的集合,无重复文章数据。
方案2:查询构造器手动组装(无需定义模型)
如果不想创建Eloquent模型,可以分两次查询后手动匹配关联,性能和联表查询一致。
$ids = [1, 2, 4, 7]; // 第一步:查询所有不重复的目标文章,以文章id为键存储 $posts = DB::connection('mysqlDatabase2') ->table('posts') ->whereIn('id_post', $ids) ->get() ->keyBy('id_post'); // 第二步:批量查询所有目标文章关联的评论,按所属文章id分组 $comments = DB::connection('mysqlDatabase2') ->table('comments') ->whereIn('id_post', $ids) ->get() ->groupBy('id_post'); // 第三步:给每篇文章挂载对应的评论数组 $data = $posts->map(function ($post) use ($comments) { $post->comments = $comments->get($post->id_post, collect())->toArray(); return $post; })->values();
不推荐使用
GROUP_CONCAT拼接评论字段的方案,该方案存在长度限制、特殊字符转义异常、大字段性能差等问题,维护成本极高。
内容的提问来源于stack exchange,提问作者jose
相关产品推荐
相关产品推荐

