2016-01-04 4 views
0

Я создаю запрос, чтобы показывать элементы с пользователем, а затем показывать самую высокую ставку по элементу.Сложный запрос join with doctrine

Пример:

Xbox 360 Джеймсом. - наивысшая ставка составляла 55 долларов США.

art table by mario. - наивысшая ставка составляла 25 долларов США.

Запрос

SELECT i, u 
FROM AppBundle:Item i 
LEFT JOIN i.user u 

У меня есть еще одна таблица ставок (один ко многим отношений). Я не уверен, как включить единую самую высокую ставку элемента в том же запросе с соединением.

Я знаю, что я могу запустить другой запрос после этого запроса с помощью функции (отношения), но я избегаю этого для оптимизации.

Решение

SQL https://stackoverflow.com/a/16538294/75799 - Но как это возможно в доктрине DQL?

+0

В качестве альтернативных идей, вам может добавить дополнительный внешний ключ для элемента к наивысшей ставке и обновить его, когда будет создана ставка, которая является новой максимальной ставкой. Это избавит вас от написания подборов и будет относительно легко реализовать. – Richard

ответ

1

Ваш SQL запрос может выглядеть как

select i,u 
from i 
inner join bids u on i.id = u.item_id 
WHERE 
    i.value = (select max(value) from bids  where item_id = i.id) 
group by i 

DQL, я не думаю, что поддерживает подзапросы, так что вы можете попробовать использовать пункт Having или увидеть, если Doctrine\ORM\Query\Expr предлагает что-нибудь.

Чтобы решить эту проблему для моего собственного случая, я добавил метод к исходному объекту (элементу), чтобы найти максимальную сущность в списке сущностей (ставок), используя Коллекции Doctrine's Criteria. Я написал об этом here.

Ваш Item объект будет содержать

public function getMaxBid() 
{ 
    $criteria = Criteria::create(); 
    $criteria->orderBy(['bid.value' => Criteria::ASC]); 
    $criteria->setLimit(1); 

    return $this->bids->matching($criteria); 
} 
+0

Спасибо за пример SQL. но мне нужно увидеть пример доктрины. потому что всегда есть что-то по-другому, что не является обычным способом sql. который я еще не экспертом. – Basit

+0

@Basit Я обновил ответ, чтобы предоставить более подробную информацию и пример кода. – bear

+0

@Basit содержит код доктрины. Возможно, вы сможете переместить это до уровня хранилища, которого я еще не пробовал. – bear

0

К сожалению, нет никакого способа, которым я знать, чтобы найти максимальную ставку и участник торгов с одной группировкой запроса, но есть несколько способов, чтобы сделать логику работы с несколькими запросами. Вы можете сделать выбор sub, и это может работать нормально, в зависимости от размера таблицы. Если вы планируете расти до такой степени, что это не сработает, вы, вероятно, уже собираетесь делиться своими реляционными базами данных, перенося некоторые данные на менее транзакционную, более высокую производительность db-технологии или денормализовать, но если вы хотите сохраните это в чистом MySQL, вы можете использовать процедуру для выражения в нескольких командах, как проверить ставку и, возможно, добавить ее в список, а также обновить текущего участника торгов в денормализованной таблице высоких ставок. Это сохраняет сложную логику того, как проверить ставку в одном, наиболее строго управляемом месте - базе данных. Просто убедитесь, что вы правильно используете транзакции, чтобы остановить одновременную запись двух ставок (например, SELECT FOR UPDATE).

Я использовал, чтобы попросить программистов написать этот запрос, чтобы узнать, насколько опытным с MySQL они были, многие думали, что достаточно максимальной группировки, и несколько оставили интервью по-прежнему убежденным, что он будет работать нормально, и i был неправильно. Так хороший вопрос!

2

В таких случаях вы можете использовать IN с дополнительным запросом.
Я не уверен, если я правильно понял вашу модель, но я попытался сделать запрос с QueryBuilder и я уверен, что вам удастся заставить его работать с этим примером:

$qb = $this->_em->createQueryBuilder(); 
$sub = $qb; 

$sub->select('mbi') // max bid item 
    ->where('i.id = mbi.id') 
    ->leftJoin('mbi.bids', 'b')) 
    ->andWhere($qb->expr()->max('b.value')) 
    ->getQuery(); 

$qb = $qb->select('i', 'u') 
     ->where($qb->expr()->in('i', $sub->getDQL())) 
     ->leftJoin('i.user', 'u'); 

$query = $qb->getQuery(); 
return $query->getResult();