Doctrine查询:如何筛选关联照片集合非空的Post?
解决Doctrine查询至少包含1张照片的Post问题
嘿,我明白你的困扰了!你之前用postPhotos != :null不生效是因为SQL里判断NULL的方式不对,而且还有更简洁高效的方法来实现需求。
为什么你的原查询不生效?
在SQL中,NULL是一个特殊值,不能用普通的比较运算符(!=、=等)来判断。当你写postPhotos != :null时,数据库会把它解析成postPhotos != NULL,而这个表达式的结果永远是unknown,所以无法正确过滤掉没有照片的Post。
方案1:用INNER JOIN替代LEFT JOIN(推荐)
最直接高效的方式是把关联照片的leftJoin改成innerJoin。因为INNER JOIN只会返回两边都有匹配记录的结果——也就是说,只有关联了至少一张Photo的Post才会被保留,完全符合你的需求:
$qb = $this->createQueryBuilder('p'); $qb->select('p, postPhotos, etc...') ->leftJoin('p.videos', 'postVideos') // 其他关联操作 if ($mediaType != null) { switch ($mediaType) { case Post::TYPE_PHOTOS: // 换成INNER JOIN,自动筛选有照片的Post $qb->innerJoin('p.photos', 'postPhotos'); break; // 处理其他mediaType的case } }
这种方式不仅逻辑清晰,查询性能也更好,因为数据库不需要先返回所有Post再过滤。
方案2:如果必须用LEFT JOIN,改用IS NOT NULL判断
如果因为业务需求(比如要保留其他关联的空数据)不能改成INNER JOIN,那你需要把判断条件改成IS NOT NULL,这才是SQL中判断非空的正确方式:
if ($mediaType != null) { switch ($mediaType) { case Post::TYPE_PHOTOS: $qb->leftJoin('p.photos', 'postPhotos') ->andWhere('postPhotos IS NOT NULL'); // 不需要setParameter传递null参数 break; } }
关于COUNT的补充说明
你提到用COUNT不可行,可能是因为没有配合GROUP BY和HAVING。如果非要用聚合的方式,写法大概是这样:
$qb->select('p') ->leftJoin('p.photos', 'postPhotos') ->groupBy('p.id') ->having('COUNT(postPhotos) > 0');
但这种方式会影响查询结果的结构(比如无法直接select关联的所有postPhotos),所以相比前面两种方案,实用性更低。
内容的提问来源于stack exchange,提问作者Brent Heigold
相关产品推荐
相关产品推荐

