I have a database with table called "message" with attributtes received, emitter, text, date. I want to select the last message that a user received, with max date.
With this code I get null value but the user have messages in the table:
$message = $this->getEntityManager()
->createQuery(
'SELECT m FROM App\Entity\Message m WHERE
m.receiver = :user
AND
m.createdAt = (SELECT MAX(m1.createdAt) FROM App\Entity\Message AS m1)
'
)
->setParameters([
'user' => $user
])
->getResult();
Your subquery doesn't include the user-condition; it fetches max(created) of messages, which is not necessarily one of the given user. But the subquery approach seems to overcomplicate things anyway.
An easier way would be: select messages of user order by created and limit to 1
in SQL
SELECT m.* FROM messages WHERE user_id=:user ORDER BY created DESC LIMIT 1
in DQL
$this
->getEntityManager()
->createQuery('SELECT m FROM App\Entity\Message m WHERE
m.receiver = :user
AND
m.createdAt = (SELECT MAX(m1.createdAt) FROM App\Entity\Message AS m1)
ORDER BY m.createdAt DESC LIMIT 1
')
->setParameters([
'user' => $user
])
->getResult();
or even simpler (using doctrine repository interface)
$entityMangager
->getRepository(Message::class)
->findOneBy(['user' => $user], ['created' => 'DESC'])
Also: Probably you want to make sure you have an index over user_id, created on that table.
Related
I need to create a query builder expression that use an IN statement where I want to put another query create by querybuilder too. In DQL, the query that i can get is:
SELECT u
FROM BundleUsuarioBundle:Usuario u
WHERE u.id IN (
SELECT u2.id
FROM BundleTramiteBundle:ExamenTeorico et
JOIN et.usuarioHabilitacion u2
WHERE u2.centro = :centro
) ORDER BY u.apellido ASC, u.nombre ASC
but i dont use that because I need put that in 'query_builder' option of an entity field of a form. So, i need a QB but I dont know how I can nest querybuilder expressions. I actually have the two queries in QueryBuilder format but separated:
$qb = $this->em->createQueryBuilder();
$qb
->select('usuario_habilitacion.id')
->from('BundleTramiteBundle:ExamenTeorico', 'examen_teorico')
->join('examen_teorico.usuarioHabilitacion', 'usuario_habilitacion');
$user = $this->getUser();
if ( !$this->esTipoASPV($user) ) {
$centro = $this->getCentro();
$qb
->andWhere($qb->expr()->eq('usuario_habilitacion.centro', ':centro'))
->setParameter(':centro', $centro->getId());
}
and:
$er
->createQueryBuilder('u')
->where($qb->expr()->in('u.id', ___???___ ))
->addOrderBy("u.apellido", "ASC")
->addOrderBy("u.nombre", "ASC");
You can get the result of your sub-query inside the first query but calling getDQL() and placing it inside a where clause in your first query. Make sure you select the id in the sub-query.
Example:
$qb->andWhere($qb->expr()->in('u.id', $er->getDQL()))
I have a Product Entity which has a ManyToMany relationship with a Taxon Entity. I want to find all the products that belong to the intersection of all Taxons. For instance I want to find all products that belong to taxons with IDs 1 and 2.
Products
{1,2,3}
Taxons
{1,2,3,4,5}
ProductsToTaxons
{{p1,t1},{p1,t2}, {p2,t2}}
I want to retrieve the following set ONLY when querying products for taxons 1 and 2:
Product
{1}
which is from {{p1,t1}, {p1,t2}}
Okay, So here is the DQL that i tried... but it doesn't work?
SELECT p FROM SRCProductBundle:Product p
JOIN p.taxons t
WHERE t.id = 1 AND t.id = 2
(P.S. I would also do this with QueryBuilder with as well)
EDIT
To clarify, here is the SQL that I would like to translate into DQL/QueryBuilder.
select p.id
from product p
where exists (select product_id
from product_to_taxon
where taxon_id = 1
and product_id = p.id)
and exists (select product_id
from product_to_taxon
where taxon_id = 4
and product_id = p.id);
You can use the MEMBER OF statement to achieve this although in my experience it hasn't produced very performant results with a ManyToMany relationship:
In DQL:
SELECT p FROM SRCProductBundle:Product p
WHERE 1 MEMBER OF p.taxons OR 2 MEMBER OF p.taxons
Or with Query builder
$this->createQueryBuilder('p')
->where(':taxon_ids MEMBER OF p.taxons')
->setParameter('taxon_ids', $taxonIdsArray)
->getQuery()
->getResult();
This will create SQL similar to the example provided although in my experience it still had a join in the EXISTS subqueries. Perhaps future versions of Doctrine can address this.
I think you want something like this:
$qb = $this
->createQueryBuilder('p')
->select('p.id')
;
$qb
->leftJoin('p.taxons', 'taxon1', Join::WITH, 'taxon1.id = :taxonId1')
->setParameter('taxonId1', 1)
->andWhere($qb->expr()->isNotNull('taxon1'))
->leftJoin('p.taxons', 'taxon2', Join::WITH, 'taxon2.id = :taxonId2')
->setParameter('taxonId2', 2)
->andWhere($qb->expr()->isNotNull('taxon2'))
;
Which is equivalent to the SQL:
SELECT p.id
FROM products p
LEFT JOIN taxons t1 ON (p.id = t1.product_id AND t1.id = 1)
LEFT JOIN taxons t2 ON (p.id = t2.product_id AND t2.id = 2)
WHERE t1.id IS NOT NULL
AND t2.id IS NOT NULL
;
Your DQL has wrong logic. You can't have a taxon with both id=1 and id=4. You could do it like this:
SELECT p FROM SRCProductBundle:Product p
JOIN p.taxons t
WHERE t.id = 1 OR t.id = 4
But I would prefer this way:
SELECT p FROM SRCProductBundle:Product p
JOIN p.taxons t
WHERE t.id IN (1, 4)
Using query builder that would look something like this, assuming you're in EntityRepository class:
$this->createQueryBuilder('p')
->join('p.taxons', 't')
->where('t.id IN :taxon_ids')
->setParameter('taxon_ids', $taxonIdsArray)
->getQuery()
->getResult();
For lack of a clean way to do this with DQL, and after a considerable amount of research, I resorted to doing this in Native SQL. Doctrine allows Native SQL via the EntityManager with createNativeQuery().
So in short, I utilized this ability and constructed the SQL query included in my question as a string and then passed it to the createNativeQuery() function.
This does appear to have some drawbacks as it appears I will be unable to use the KnpPaginatorBundle with it... So I might end up just filtering the results in PHP rather than SQL, which I'm hesitant to do as I think there are performance drawbacks.
I know that similar question was asked 3 years ago (Doctrine2 Order By before Group By) but maybe from that time something changed.
i have 2 entity propertes:
orderId
orderUpdateDate
both as a pair are set to be unique, but for listing I need last update date so sorting should be
order by orderUpdateDate DESC
and then grouped by orderId so I have orders only once.
group by orderId
problem is such that when I paste both in one query in query builder I got random listing of orders
To achieve such a result you'd have to end up with following SQL query:
SELECT n.id, n.update_date
FROM (
SELECT o.id, o.update_date
FROM orders o
ORDER BY o.update_date DESC
) n
GROUP BY n.id;
Unfortunately Doctrine's DQL doesn't support nested queries in FROM clause. However, it allows you to create a custom, native SQL query that can be mapped by ORM:
$rsm = new ResultSetMappingBuilder($em);
$rsm->addRootEntityFromClassMetadata('MyProject\\Order', 'o');
$sql = sprintf('SELECT %s FROM (SELECT ...) GROUP BY ...', $rsm->generateSelectClause());
$query = $em->createNativeQuery($sql, $rsm);
$result = $query->getResult();
I'm working on a Symfony 2/Doctrine project that has to use a legacy database. I've created a Doctrine 2 entity form the existing database which generally works just fine. But I can't seem to get one case working: There are some database entries that have empty field (not NULL, just empty) which I want to select via a Doctrine query.
$em = $this->getDoctrine()->getManager();
$query = $em->createQuery(
'SELECT p FROM dtrcmsBundle:Page p WHERE p.articleName = :pageName'
)->setParameter('pageName', '');
Dose not seem to work. Any ideas how to select the empty fields?
As empty string is less than any character(I may be wrong) so we can compare with the lowest character in the character-encoding scheme, '0'. Following example shows what I mean.
$em = $this->getDoctrine()->getManager();
$query = $em->createQuery(
'SELECT p FROM dtrcmsBundle:Page p WHERE p.articleName < :pageName'
)->setParameter('pageName', '0');
I want to do something like that into Doctrine SQL...
SELECT N.id as n_id, C.id as c_id, T.id as t_id, C.author_id, C.body as comment FROM `news` N
LEFT JOIN thread T on T.id = N.id
LEFT JOIN comment C on C.thread_id = T.id
WHERE 1
So I have made this :
$rsm = new ResultSetMapping;
$rsm->addEntityResult('App\MyBundle\Entity\News', 'N');
$cols = array ('id', 'title','date');
foreach ($cols as $key => $col) {
$rsm->addFieldResult('N', $col, $col);
}
// thread
$rsm->addJoinedEntityResult('App\MyBundle\Entity\Thread' , 'T', 'N', 'thread');
$rsm->addFieldResult('T', 't_id', 'id');
$sql = 'SELECT N.id, N.title, N.date, T.id AS t_id FROM news N ' .
'LEFT JOIN thread T ON T.id = N.id WHERE N.id = 1';
$query = $this->_em->createNativeQuery($sql, $rsm);
But I have an error:
Notice: Undefined index: thread in /vendor/doctrine/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php line 85
I want to precise that there is no member link beetween the 2 entities.
Any ideas please?
Thanks for all
See ya
Sam
According to the docs:
The fourth and last parameter is the name of the field on the parent entity result that should contain the joined entity result.
ref: http://www.doctrine-project.org/docs/orm/2.1/en/reference/native-sql.html#joined-entity-results
you maybe missed to define the thread property in the News class that will receive your joined entity.