Порядок внутри группы в Учении 2 - PullRequest
6 голосов
/ 24 апреля 2011

Я использую Symfony 2 PR12 с Doctrine 2 и MySQL.У меня есть база данных, в которой хранятся статьи и просмотры этих статей:

// ...
class Article {

    /**
     * @orm:Column(type="bigint")
     * @orm:Id
     * @orm:GeneratedValue
     * @var int
     */
    protected $id;

    /**
     * @orm:OneToMany(targetEntity="ArticleView",mappedBy="article")
     * @var ArrayCollection
     */
    protected $views;

    // ...
}

// ...
class ArticleView {

    /**
     * @orm:Column(type="bigint")
     * @orm:Id
     * @orm:GeneratedValue
     * @var int
     */
    protected $id;

    /**
     * @orm:Column(type="bigint",name="DateRead",nullable=true)
     * @var int
     */
    protected $viewDate;

    /**
     * @orm:ManyToOne(targetEntity="Article",inversedBy="views")
     * @var Article
     */
    protected $article;

    // ...
}

Я хочу получить, например, 20 самых последних просмотренных статей.Моей первой мыслью было бы что-то вроде:

$qb = <instance of Doctrine\ORM\QueryBuilder>;
$qb->select('a')
   ->from('Article', 'a')
   ->join('a.views', 'v')
   ->orderBy('v.viewDate', 'DESC')
   ->groupBy('a.id')
   ->setMaxResults(20)
;

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

Это ожидаемое поведение для MySQL, так как группировка обрабатывается перед упорядочением, и есть рабочие решения для необработанных запросов в http://www.artfulsoftware.com/infotree/mysqlquerytree.php (Агрегаты -> Внутригрупповые агрегаты).Но я не могу понять, как перевести какое-либо из этих решений на DQL, поскольку, насколько я могу судить, нет способа выбрать из подзапросов или выполнить самоисключение.

Любые идеи о том, как решитьпроблема с разумной производительностью?

1 Ответ

8 голосов
/ 29 апреля 2011

В итоге я решил ее с помощью коррелированного подзапроса:

$qb
    ->select('a')
    ->from('Article', 'a')
    ->join('a.views', 'v')
    ->orderBy('v.viewDate', 'DESC')
    ->setMaxResults(20)

    // Only select the most recent article view for each individual article
    ->where('v.viewDate = (SELECT MAX(v2.viewDate) FROM ArticleView v2 WHERE v2.article = a)')

Таким образом, сортировка игнорирует ArticleView, отличный от самой последней для любой данной статьи.Хотя я предполагаю, что по сравнению с другими необработанными решениями SQL это работает довольно плохо - любые ответы с более высокой производительностью все равно будут высоко оценены:).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...