4

I want to use DQL to create a query which looks like this in SQL:

select
    e.*
from
    e
inner join (
    select
        uuid, max(locale) as locale
    from
        e
    where
        locale = 'nl_NL' or
        locale = 'nl'
    group by
        uuid
) as e_ on e.uuid = e_.uuid and e.locale = e_.locale

I tried to use QueryBuilder to generate the query and subquery. I think they do the right thing by them selves but I can't combine them in the join statement. Does anybody now if this is possible with DQL? I can't use native SQL because I want to return real objects and I don't know for which object this query is run (I only know the base class which have the uuid and locale property).

    $subQueryBuilder = $this->_em->createQueryBuilder();
    $subQueryBuilder
        ->addSelect('e.uuid, max(e.locale) as locale')
        ->from($this->_entityName, 'e')
        ->where($subQueryBuilder->expr()->in('e.locale', $localeCriteria))
        ->groupBy('e.uuid');

    $queryBuilder = $this->_em->createQueryBuilder();
    $queryBuilder
        ->addSelect('e')
        ->from($this->_entityName, 'e')
        ->join('('.$subQueryBuilder.') as', 'e_')
        ->where('e.uuid = e_.uuid')
        ->andWhere('e.locale = e_.locale');
Martijn de Munnik
  • 924
  • 12
  • 23
  • Doing an INNER JOIN on a subquery is exactly [what I'm trying to do](http://stackoverflow.com/questions/27007090/inner-join-results-from-select-statement-using-doctrine-querybuilder). Did you find a solution? – Chadwick Meyer Nov 20 '14 at 17:55

1 Answers1

0

You cannot put a subquery in the FROM clause of your DQL.

I will assume that your PK is {uuid, locale}, as of discussion with you on IRC. Since you also have two different columns in your query, this can become ugly. What you can do is putting it into the WHERE clause:

select
    e
from
    MyEntity e
WHERE
    e.uuid IN (
        select
            e2.uuid
        from
            MyEntity e2
        where
            e2.locale IN (:selectedLocales)
        group by
            e2.uuid
    )
    AND e.locale IN (
        select
            max(e3.locale) as locale
        from
            MyEntity e3
        where
            e3.locale IN (:selectedLocales)
        group by
            e3.uuid
    )

Please note that I used a comparison against a (non empty) array of locales that you bind to to the :selectedLocales. This is to avoid destroying the query cache if you want to match against additional locales.

I also wouldn't suggest building this with the query builder if there's no real advantage in doing so since it will just make it simpler to break the query cache if you add conditionals dynamically (also, it's 3 query builders involved!)

Ocramius
  • 25,171
  • 7
  • 103
  • 107
  • I don't think this is going to work because there is no relation between the uuid and the locale for each row in the result. – Martijn de Munnik Oct 31 '12 at 21:22
  • Yes, you're right... this won't really work. It may be possible to `concat` the `uuid` and the `locale` field and then do the check, but any keys will be useless in such a case (and it's not even a good solution) – Ocramius Oct 31 '12 at 21:37