我有一个允许在很多方面评价公司的项目。下图可以帮助您了解我的数据库中的关系。当然,我已从方案中删除了在我的问题背景下不重要的字段。
目前,在Company
实体的我的存储库类中,我正在使用QueryBuilder
搜索公司并返回\Doctrine\ORM\Tools\Pagination\Paginator
的实例。
以下代码负责提取公司:
public function search(CompanySearchQuery $command): Paginator
{
$qb = $this->createQueryBuilder('c')
->setFirstResult($command->getOffset())
->setMaxResults($command->getMaxResults())
->orderBy('c.name', 'ASC');
... plus extra "where" conditions
return new Paginator($qb, true);
}
我想知道如何使用QueryBuilder
和Paginator
将平均分数附加到每家公司。
这是允许我获取所需数据的本机SQL:
SELECT
c.id,
c.name,
AVG(o2.score) as score
FROM
company c
LEFT JOIN
opinion o ON c.id = o.company_id
LEFT JOIN
opinion_scope o2 ON o.id = o2.opinion_id
GROUP BY
c.id
我的问题是:是否可以将averageScore
属性添加到Company
类并从QueryBuilder
结果中映射?
我尝试重写我的SQL查询以与现有代码一起使用:
$qb = $this->createQueryBuilder('c')
->select('c', 'AVG(s.score)')
->leftJoin('c.opinions', 'o')
->leftJoin('o.scopes', 's')
->groupBy('c.id')
->setFirstResult($command->getOffset())
->setMaxResults($command->getMaxResults())
->orderBy('c.name', 'ASC')
;
使用上面的代码我得到如下数据库异常:
SQLSTATE[42000]: Syntax error or access violation: 1055 Expression #14 of
SELECT list is not in GROUP BY clause and contains nonaggregated column
'database.o1_.score' which is not functionally dependent on columns in GROUP BY
clause; this is incompatible with sql_mode=only_full_group_by").
为上述QueryBuilder执行的SQL查询是:
SELECT
DISTINCT id_8
FROM
(
SELECT
DISTINCT id_8,
name_9
FROM
(
SELECT
c0_.updated_at AS updated_at_0,
c0_.description AS description_1,
c0_.website AS website_2,
c0_.email AS email_3,
c0_.phone AS phone_4,
c0_.street AS street_5,
c0_.postal_code AS postal_code_6,
c0_.city AS city_7,
c0_.id AS id_8,
c0_.name AS name_9,
c0_.slug AS slug_10,
c0_.created_at AS created_at_11,
AVG(o1_.score) AS sclr_12,
o1_.score AS score_13,
o1_.opinion_id AS opinion_id_14,
o1_.type_id AS type_id_15
FROM
company c0_
LEFT JOIN opinion o2_ ON c0_.id = o2_.company_id
LEFT JOIN opinion_scope o1_ ON o2_.id = o1_.opinion_id
GROUP BY
c0_.id
) dctrn_result_inner
ORDER BY
name_9 ASC
) dctrn_result
LIMIT
2 OFFSET 0
我不明白为什么Doctrine会添加以下片段:
o1_.score AS score_13,
o1_.opinion_id AS opinion_id_14,
o1_.type_id AS type_id_15
答案 0 :(得分:0)
问题似乎是你试图从'c'中选择每一列,这是你执行两个LEFT JOIN的结果表。相反,您需要为公司表指定from子句:
$qb = $this->createQueryBuilder()
->select('c', 'AVG(s.score)')
->from('company', 'c')
->leftJoin('c.opinions', 'o')
->leftJoin('o.scopes', 's')
->groupBy('c.id')
->setFirstResult($command->getOffset())
->setMaxResults($command->getMaxResults())
->orderBy('c.name', 'ASC')
;
这将避免包括o1.score是您返回的列,这是该错误引用的