Doctrine2中addSelect子查询返回多行的问题咨询
解决Doctrine中子查询返回多行的基数违反错误
当然可以实现返回多行的需求!你遇到的SQLSTATE[21000]: Cardinality violation: 1242错误,本质是因为你把一个会返回多行结果的子查询放在了SELECT列表里——不管是Doctrine还是底层数据库,都默认这个位置的子查询应该返回单个标量值,所以当子查询返回多行时就会触发错误,Doctrine把它标记为sclr_7(标量的意思)也印证了这一点。
根据你的实际需求,有几种不同的解决思路:
1. 用IN/EXISTS判断匹配关系
如果你的需求是筛选出存在对应流派的电影(或者反过来),可以把子查询放到WHERE子句的IN或EXISTS条件里,这样数据库会接受子查询返回的多行结果:
Doctrine QueryBuilder示例:
// 主查询:筛选出有对应流派的电影 $mainQb = $this->createQueryBuilder('m'); // 子查询:获取当前电影关联的流派ID $subQb = $this->createQueryBuilder('m2') ->select('mg.id') ->join('m2.movieGenres', 'mg') ->where('m2.id = m.id'); // 使用IN条件关联子查询 $mainQb->where($mainQb->expr()->in('m.id', $subQb->getDQL())) ->getQuery() ->getResult();
2. 用GROUP_CONCAT合并多行结果为单个字段
如果需要在主查询的每行结果里,附带对应电影的所有流派ID(比如作为逗号分隔的字符串),可以用GROUP_CONCAT函数把多行子查询结果合并成单个标量值,这样就能放在SELECT列表里了:
SQL原生示例:
SELECT m0_.id, GROUP_CONCAT(m2_.id SEPARATOR ',') AS genre_ids FROM movies m0_ LEFT JOIN moviesgenres_movies m4_ ON m0_.id = m4_.movies_id LEFT JOIN movie_genres m2_ ON m2_.id = m4_.moviesgenres_id GROUP BY m0_.id
Doctrine QueryBuilder示例:
$qb = $this->createQueryBuilder('m') ->select('m.id', 'GROUP_CONCAT(mg.id SEPARATOR \',\') AS genreIds') ->leftJoin('m.movieGenres', 'mg') ->groupBy('m.id') ->getQuery() ->getResult();
之后你可以在代码里把genreIds字符串拆分成数组,获取所有流派ID。
3. 将子查询作为派生表放到FROM子句中
如果确实需要返回多行结果(比如每个电影-流派的关联行),应该把子查询作为派生表放到FROM子句中,而不是SELECT列表里:
SQL原生示例:
SELECT m.id, sub.genre_id FROM movies m LEFT JOIN ( SELECT m4_.movies_id, m2_.id AS genre_id FROM movie_genres m2_ LEFT JOIN moviesgenres_movies m4_ ON m2_.id = m4_.moviesgenres_id ) AS sub ON m.id = sub.movies_id
Doctrine QueryBuilder示例:
// 构建子查询作为派生表 $subQb = $this->getEntityManager()->createQueryBuilder() ->select('m4.moviesId', 'mg.id AS genreId') ->from('App\Entity\MovieGenres', 'mg') ->leftJoin('mg.movies', 'm4'); // 主查询关联派生表 $mainQb = $this->createQueryBuilder('m') ->select('m.id', 'sub.genreId') ->leftJoin( sprintf('(%s)', $subQb->getDQL()), 'sub', \Doctrine\ORM\Query\Expr\Join::WITH, 'm.id = sub.moviesId' ) ->getQuery() ->getResult();
这样查询结果会返回每个电影对应的所有流派ID的多行数据,完全满足你返回多行的需求。
内容的提问来源于stack exchange,提问作者Anastasia Sitnina
相关产品推荐
相关产品推荐

