Доктрина: получить с 1: n ассоциацией с count () и sum () - PullRequest
0 голосов
/ 07 марта 2012

У меня есть посредник с отношением 1: n к объекту деятельности.

Каждое действие, выполняемое посредником, имеет значение.

Что я хочу сделать, так это собрать всех посредников с общей суммой стоимости его деятельности и подсчетом количества действий за определенный месяц и за весь год.

Я пытался с помощью построителя запросов:

$qb = $this->getEntityManager()->createQueryBuilder();
$qb
    ->select(array(
        'u.id', 
        'u.name', 
        'u.reseller_code', 
        'u.first_name',
        'u.last_name',
        'u.email',
        'u.country',
        'COUNT(am) as numam', 
        'SUM(ay.activity_value) as sumay', 
        'SUM(am.activity_value) as sumam'
        ))
    ->from('MyBundle:User', 'u')
    ->leftJoin('u.activities', 'ay', 'WITH', 'ay.activity_year = :year')
    ->leftJoin('u.activities', 'am', 'WITH', 'am.activity_month = :month AND am.activity_year = :year')
    ->groupBy('u.id')
    ->orderBy('u.name', 'ASC')
    ->setParameter('month', $month)
    ->setParameter('year', $year)
;

Полученный запрос:

SELECT p0_.id AS id0, p0_.name AS name1, p0_.reseller_code AS reseller_code2, p0_.first_name AS first_name3, 
p0_.last_name AS last_name4, p0_.email AS email5, p0_.country AS country6, COUNT(a1_.id) AS sclr7, 
SUM(a2_.activity_value) AS sclr8, SUM(a1_.activity_value) AS sclr9 
FROM reseller p0_ 
LEFT JOIN activity a2_ ON p0_.id = a2_.reseller_id AND (a2_.activity_year = ?) 
LEFT JOIN activity a1_ ON p0_.id = a1_.reseller_id AND (a1_.activity_month = ? AND a1_.activity_year = ?) 
GROUP BY p0_.id 
ORDER BY p0_.name ASC ([2012,"2",2012])

Но результат не верный, я получаю цифры, такие как 90 вместо 20 действий и суммы 900 вместо 90.

Где я не прав? Спасибо за любую помощь!

Ответы [ 2 ]

2 голосов
/ 08 марта 2012

Я думаю, что это проблема SQL, а не доктрина. Вы используете JOIN два раза на одной и той же таблице с пересекающимися условиями. Таким образом, вы получаете дубликаты записей и неверные результаты для ваших расчетов.

Я думаю, это может сработать:

$qb = $this->getEntityManager()->createQueryBuilder();
$qb
    ->select(array(
        'u.id', 
        'u.name', 
        'u.reseller_code', 
        'u.first_name',
        'u.last_name',
        'u.email',
        'u.country',
        'COUNT(am) as numam', 
        'SUM(IF(a.activity_year = :year, a.activity_value, 0)) as sumay', 
        'SUM(IF(a.activity_year = :year AND a.activity_month = :month, a.activity_value, 0)) as sumam'
        ))
    ->from('MyBundle:User', 'u')
    ->leftJoin('u.activities', 'a')
    ->groupBy('u.id')
    ->orderBy('u.name', 'ASC')
    ->setParameter('month', $month)
    ->setParameter('year', $year)
;

По сути, идея состоит в том, чтобы ПРИСОЕДИНИТЬСЯ только один раз, и сделать ваши вычисления в SUM().

Редактировать: Кстати, поскольку вы сказали 1:n отношение, JOIN может быть лучше, чем LEFT JOIN

1 голос
/ 20 марта 2013

Немного поздно, но CASE в настоящее время поддерживается Doctrine 2; поэтому IF можно заменить на CASE для достижения того же результата, если это необходимо.

, например

...

'SUM(CASE a.activity_year WHEN :year THEN a.activity_value ELSE 0 END) as sumay',

...

...