Преобразование MySQL с подзапросами в DQL 1.2

Привет, у меня есть следующий запрос из предыдущий вопрос и необходимо преобразовать его в DQL для Doctrine 1.2. Однако оказывается, что DQL не поддерживает подзапросы в соединениях.

SELECT * FROM contact c
  LEFT JOIN
    (SELECT a1.contact_id, a1.date, a1.activity_type_id FROM activity a1
      JOIN (SELECT contact_id, MAX(DATE) DATE FROM activity GROUP BY contact_id) a2
        ON a1.contact_id = a2.contact_id AND a1.date = a2.date
     ) a
  ON c.id = a.contact_id  

WHERE a.activity_type_id = 2;

Я пытаюсь понять, как сделать это по-другому, не прибегая к нескольким запросам.

Спасибо.


person Ben    schedule 07.08.2012    source источник
comment
Вам разрешено использовать представление вместо подзапроса?   -  person Neil    schedule 08.08.2012
comment
Я никогда не использовал точку зрения, но доктрина, похоже, поддерживает ее.   -  person Ben    schedule 08.08.2012
comment
Я читал о представлениях в доктрине, и это не решит ее для меня. Мне придется попытаться переписать это как запрос DQL, но я не знаю, возможно ли это сделать.   -  person Ben    schedule 08.08.2012
comment
Итак, можете ли вы, например, создать представление CREATE VIEW max_activity_date AS SELECT contact_id, MAX(date) AS max_date FROM activity GROUP BY contact_id и присоединиться к нему?   -  person Neil    schedule 09.08.2012
comment
У меня получилось переписать. Просмотры не работали, но я смог сделать это по-другому. Спасибо.   -  person Ben    schedule 10.08.2012


Ответы (2)


Используя доктрину, вы не должны вкладывать подзапросы в условие where, используя необработанный sql. Вы столкнетесь с проблемами в более сложных сценариях. Вместо этого используйте createSubquery, чтобы явно сообщить доктрине о подзапросе, позвольте доктрине скомпилировать ее в DQL, а затем вложить в ваше условие where. Таким образом, ваш запрос должен выглядеть примерно так:

$q->from('Contact c') 
  ->leftJoin('c.Activity a')
;

$subquery = $q->createSubquery()
    ->select("a1.contact_id, MAX(a1.date) a1.date")
    ->from("Activity a1")
    ->groupby("a1.contact_id")
;

$q->where('ROW (c.id, date) IN ('.$subquery->getDql().')')
  ->andWhere('a.activity_type_id = ?', $filterActivityTypeId)
;

Другой пример можно найти здесь:

https://www.philipphoffmann.de/2012/08/29/a-bulletproof-pattern-for-creating-doctrine-subqueries-of-any-complexity/

person philipphoffmann    schedule 01.09.2012

Окончательный запрос:

SELECT * FROM contact c
    LEFT JOIN activity ON c.id = contact_id
    WHERE ROW (c.id,DATE) IN (SELECT contact_id, MAX(date) date FROM activity  GROUP BY contact_id)
    AND activity_type_id = 2

Окончательный ДКЛ:

$q->from('Contact c') 
->leftJoin('c.Activity a')      
->where('ROW (c.id, date) IN (SELECT a1.contact_id, MAX(a1.date) a1.date FROM Activity a1 GROUP BY a1.contact_id)')
->andWhere('a.activity_type_id = ?', $filterActivityTypeId);
person Ben    schedule 10.08.2012