求正确SQL/Symfony DQL语句:按唯一公司计算金额总和
解决方案:关联车辆用户所属公司的amount去重求和
问题根源
多表关联时,同一公司会因关联多个用户/车辆而重复出现在结果集中,导致SUM(amount)重复计算该公司的数值。比如用户1、2同属公司1(amount=1000),另一个公司2(amount=1000),未去重的关联会让公司1的amount被计算两次,最终得到1000*2+1000=3000,而正确结果应为1000+1000=2000。
原生SQL解决方案
方案1:子查询获取去重公司后求和(最稳妥,避免金额重复问题)
先筛选出所有关联车辆的用户所属的唯一公司ID,再基于这些ID求和公司的amount:
SELECT SUM(c.amount) AS total_amount FROM companies c WHERE c.id IN ( SELECT DISTINCT uc.company_id FROM cars ca JOIN car_users cu ON ca.id = cu.car_id JOIN users u ON cu.user_id = u.id JOIN user_companies uc ON u.id = uc.user_id );
方案2:关联后去重求和(注意:若不同公司amount相同,SUM(DISTINCT)会合并相同数值)
直接关联所有表,通过DISTINCT确保每个公司的amount只被计算一次:
SELECT SUM(DISTINCT c.amount) AS total_amount FROM cars ca JOIN car_users cu ON ca.id = cu.car_id JOIN users u ON cu.user_id = u.id JOIN user_companies uc ON u.id = uc.user_id JOIN companies c ON uc.company_id = c.id;
Symfony DQL实现方案
假设实体映射关系如下:
Car与User为多对多关联(通过car_users表,Car类含$users属性)User与Company为多对多关联(通过user_companies表,User类含$companies属性)
方案1:子查询去重公司后求和
$entityManager = $this->getDoctrine()->getManager(); $dql = <<<DQL SELECT SUM(c.amount) AS totalAmount FROM App\Entity\Company c WHERE c.id IN ( SELECT DISTINCT uc.id FROM App\Entity\Car ca JOIN ca.users u JOIN u.companies uc ) DQL; $query = $entityManager->createQuery($dql); $totalAmount = $query->getSingleScalarResult();
方案2:分组公司后求和
先按公司ID分组确保每个公司唯一,再对分组后的amount求和:
$entityManager = $this->getDoctrine()->getManager(); $dql = <<<DQL SELECT SUM(sub.amount) AS totalAmount FROM ( SELECT c.amount AS amount FROM App\Entity\Car ca JOIN ca.users u JOIN u.companies c GROUP BY c.id ) sub DQL; $query = $entityManager->createQuery($dql); $totalAmount = $query->getSingleScalarResult();
简化写法(利用分组直接求和)
当按公司ID分组后,每个分组仅对应一个公司,此时直接对分组内的amount求和即可得到总结果:
$entityManager = $this->getDoctrine()->getManager(); $dql = <<<DQL SELECT SUM(c.amount) AS totalAmount FROM App\Entity\Car ca JOIN ca.users u JOIN u.companies c GROUP BY c.id DQL; // 累加分组后的结果 $results = $query->getResult(); $totalAmount = array_reduce($results, fn($sum, $item) => $sum + $item['totalAmount'], 0);
内容的提问来源于stack exchange,提问作者Darkness007
相关产品推荐
相关产品推荐

