I am trying to JOIN 2 queries in DQL but I am getting an error which says,
[Semantical Error] line 0, col 114 near '(select u.email': Error: Class '(' is not defined.
I have gone through https://stackoverflow.com/questions/24600439/error-in-nested-subquery-in-dql-class-is-not-defined. But I could not figure out. Please help.
My Query is as follows:
$filterQuery = "SELECT tempResult1.email as email,tempResult1.name as name , tempResult1.id as user
FROM (select u.email as email,a.name as name , u.id as user
FROM
Application\Entity\Userhasrole uhr
INNER JOIN
Application\Entity\Oauthrole r with uhr.applicationrole = r.id
INNER JOIN
Application\Entity\Application a with r.application = a.id
INNER JOIN
Application\Entity\Oauthusers u
) tempResult1
LEFT JOIN
(SELECT uhr1.user as user FROM Application\Entity\Userhasrole uhr1 where
a.id = :applicationId
) tempResult2
with tempResult1.user = tempResult2.user";
$queryObject = $this->getEntityManager()
->createQuery($filterQuery);
$queryObject->setParameter('applicationId', $applicationId);
$result = $queryObject->getResult();
You mix 2 concepts of Doctrine2 :
using SQL
using DQL
If you want to achieve that you want, build tables selections, and not entities selections, you should use EntityManager::createNativeQuery() method and set an SQL query as parameter.
EntityManager::createQuery() is used only for DQL queries
Related
i'm with an small problem... I created an query on SQL that works perfectly.
I need an column on query result, that tells me if this row, exists in another row, and group by user_id.
this is my query at moment:
select u.*,
case when m.usuario_id = u.id
then 1
else 0
end as posicionado
from usuario u
left join ( select usuario_id from matriz where matriz = 1 ) as m
on u.id = m.usuario_id group by u.id
But when i try convert do DQL, it gives a problem on left join ( select.
Here is my actual DQL:
SELECT u,
CASE WHEN IDENTITY(m.usuario) = u.id
THEN 1
ELSE 0
END AS posicionado
FROM AppBundle:Usuario u
LEFT JOIN (SELECT IDENTITY (ma.usuario_id) FROM AppBundle:Matriz ma WHERE ma.matriz = 1) as m ON u.id = m.usuario_id group by u.id
It seens like if Doctrine cant understand that query. This is the error:
[Semantical Error] line 0, col 206 near '(SELECT
IDENTITY(ma.usuario_id)': Error: Class '(' is not defined.
Can someone help me understand how to use Querys on JOIN with Doctrine?
I need it to use with KNPPaginationBundle. And it does not work with raw SQL.
Try not using the Identity function. You don't need it since you're selecting from Matriz. But still I would remove inner select and use on like below:
SELECT u,
CASE WHEN IDENTITY(m.usuario) = u.id
THEN 1
ELSE 0
END AS posicionado
FROM AppBundle:Usuario u
LEFT JOIN AppBundle:Matriz ma ON ma.matriz = 1 AND m.usario_id = u.id
group by u.id
Also if you'll show your entities I could improve the join.
I have some One-To-Many, unidirectional with Join Table relationships in a Symfony App which I need to query and I can't figure out how to do that in DQL or Query Builder.
The Like entity doesn't have a comments property itself because it can be owned by a lot of different types of entities.
Basically I would need to translate something like this:
SELECT likes
FROM AppBundle:Standard\Like likes
INNER JOIN comment_like ON comment_like.like_id = likes.id
INNER JOIN comments ON comment_like.comment_id = comments.id
WHERE likes.created_by = :user_id
AND likes.active = 1
AND comments.id = :comment_id
I've already tried this but the join output is incorrect, it selects any active Like regardless of its association with the given comment
$this->createQueryBuilder('l')
->select('l')
->innerJoin('AppBundle:Standard\Comment', 'c')
->where('l.owner = :user')
->andWhere('c = :comment')
->andWhere('l.active = 1')
->setParameter('user', $user)
->setParameter('comment', $comment)
I see 2 options to resolve this:
Make relation bi-directional
Use SQL (native query) + ResultSetMapping.
For the last option, here is example of repository method (just checked that it works):
public function getLikes(Comment $comment, $user)
{
$sql = '
SELECT l.id, l.active, l.owner
FROM `like` l
INNER JOIN comment_like ON l.id = comment_like.like_id
WHERE comment_like.comment_id = :comment_id
AND l.active = 1
AND l.owner = :user_id
';
$rsm = new \Doctrine\ORM\Query\ResultSetMappingBuilder($this->_em);
$rsm->addRootEntityFromClassMetadata(Like::class, 'l');
return $this->_em->createNativeQuery($sql, $rsm)
->setParameter('comment_id', $comment->getId())
->setParameter('user_id', $user)
->getResult();
}
PS: In case of Mysql, 'like' is reserved word. So, if one wants to have table with name 'like' - just surround name with backticks on definition:
* #ORM\Table(name="`like`")
I find the Symfony documentation very poor about unidirectional queries.
Anyway I got it working by using DQL and sub-select on the owning entity, which is certainly not as fast. Any suggestion on how to improve that is more than welcomed!
$em = $this->getEntityManager();
$query = $em->createQuery('
SELECT l
FROM AppBundle:Standard\Like l
WHERE l.id IN (
SELECT l2.id
FROM AppBundle:Standard\Comment c
JOIN c.likes l2
WHERE c = :comment
AND l2.owner = :user
AND l2.active = 1
)'
)
->setParameter('user', $user)
->setParameter('comment', $comment)
;
I have an issue with DQL in Doctrine 2.
Subqueries seem to be unavailable in DQL, so I don't know how to transform :
SELECT DISTINCT a.ID_DOMAINE, L_DOMAINE, b.ID_SS_DOMAINE, L_SS_DOMAINE, c.ID_COMPETENCE, L_COMPETENCE
FROM ((qfq_prod.REF_DOMAINE a inner join qfq_prod.REF_SS_DOMAINE b on a.id_domaine = b.id_domaine)
inner join qfq_prod.REF_COMPETENCE c on b.id_ss_domaine = c.id_ss_domaine)
inner join qfq_prod.REF_PERS_COMP d on c.id_competence = d.id_competence
into a DQL expression.
I tried it and got
"Error: Class '(' is not defined."
I saw that we can use Query Builder to do this as well.
Being new with Doctrine 2, can someone explain to me how I can do this please ?
My DQL is currently :
$query = $this->getEntityManager()->createQuery ( "SELECT DISTINCT a.ID_DOMAINE, L_DOMAINE, b.ID_SS_DOMAINE, L_SS_DOMAINE, c.ID_COMPETENCE, L_COMPETENCE
FROM ((BdDoctrine\Entity\Domaine a inner join BdDoctrine\Entity\SsDomaine b on a.id_domaine = b.id_domaine)
inner join BdDoctrine\Entity\Competence c on b.id_ss_domaine = c.id_ss_domaine)
inner join BdDoctrine\Entity\LienPersComp d on c.id_competence = d.id_competence" );
$res = $query->getResult ();
Subqueries seem to be unavailable in DQL, so I don't know how to transform :
Actually, they are. Your code (no offence) is hardly readable so I will give you an example:
//controller
$repo = $this->getDoctrine()->getRepository("Your:Bundle:Category") ;
$results = $repo->findAllForSomePage() ;
// CategoryRepository.php
public function findAllForSomePage()
{
return $this->createQueryBuilder("o")
->innerJoin("o.products", "p", "WITH", "p.price>:price")->addSelect("p")
->setParameter("price", 50)
->where("o.id IN (SELECT s1.id FROM Your:Bundle:Something s1 WHERE s1.col1=5)")
->getQuery()->getResult() ;
}
Here is presumed you have Category hasMany Products relation and that you defined CategoryRepository file. You should never create queries in controller.
This example will fetch Categories only if they have Products with price bigger than 50, AND the ID of categories are those fetched by fictional subquery. This 100% works.
You should apply the same logic on your requirement.
Also, you should not use ON statement when using joins, that is handled by doctrine.
If you have the relationships properly defined in your entities, then you can make your joins on those relationships. And as Zeljko mentioned, you don't need to specify the ON condition, as the entities should already know how they are related. You are joining entities not tables. (That's under the hood.)
I don't know what your entities look like, so I made a guess at the relationship names below, but it should give you the idea.
$dql =
<<<DQL
SELECT
DISTINCT a.ID_DOMAINE, b.L_DOMAINE, b.ID_SS_DOMAINE, b.L_SS_DOMAINE, c.ID_COMPETENCE, c.L_COMPETENCE
FROM
BdDoctrine\Entity\Domaine a
JOIN a.ss_domaine b
JOIN b.competence c
JOIN c.lien_pers_comp d
DQL;
$query = $this->getEntityManager()->createQuery($dql);
$res = $query->getResult();
I have 3 tables with column
A:
id
B:
id
a_id
C:
id
b.id
with native query:
SELECT a.id, b.id, c.id
FROM A as a
LEFT JOIN B as b
INNER JOIN C as c ON b.id = c.b_id
ON a.id = b.a_id
i have tried
SELECT a.id, b.id, c.id
FROM App\HomeBundle\Entity\A as a
LEFT JOIN App\HomeBundle\Entity\B as b
INNER JOIN App\HomeBundle\Entity\C as c
ON c.id = c.bId
ON a.id = b.aId
i got error:
Error: Expected Literal, got 'JOIN'
Is it possible to convert my native query to DQL or query builder? If possible, how it will be look like?
This is only a guess but too long for a comment. If I'm completely off base I'll delete this answer.
Assuming your native query is syntactically correct, perhaps MySQL is applying the last ON condition to the result of an INNER JOIN between b and c. If that's true, see if this gives you the same result:
SELECT a.id, b.id, c.id
FROM App\HomeBundle\Entity\A as a
LEFT JOIN (
SELECT bx.aID
FROM App\HomeBundle\Entity\B as bx
INNER JOIN App\HomeBundle\Entity\C as c
ON bx.id = c.bId
) b
ON a.id = b.aId
Note I corrected what I believe to be an error in your attempted solution (where you said ON c.id = c.bId).
This is an older question, but I believe you need to JOIN on the relationship, and not the entity.
For example, instead of
SELECT a
FROM Entity\A as a
LEFT JOIN Entity\B as b
It should be:
SELECT a
FROM Entity\A as a
LEFT JOIN a.entityB as b
If that is not clear, a.entityB is a property of the A entity, called "entityB". That property defines the relationship between A and B.
When you just JOIN entity to entity, Doctrine does not know how they are related. However, if you JOIN based on the property, Doctrine can use the annotations (or other mapping) to determine the relationship of A and B.
I've always had to use the WITH keyword instead of ON when using doctrine.
I want to implement this SQL using doctrine2 query builder:
SELECT c.*, COUNT(s.id) AS studentCount
FROM classes c
LEFT JOIN (
SELECT *
FROM student_classes
WHERE YEAR = '2012'
) sc ON c.id = sc.class_id
LEFT JOIN students s ON sc.student_id = s.id
GROUP BY c.id
I tried this one but didn't work
$qb = $this->getEntityManager()
->getRepository('Classes')
->createQueryBuilder('c');
$qb->select('c.id AS id, c.name AS name, COUNT(s) AS studentCount');
$qb->leftJoin(
$qb->select('sc1')
->from('StudentClasses', 'sc1')
->where('sc1.year = :year')
->setParameter('year', $inputYear),
'sc2'
);
$qb->leftJoin('sc2.students', 's');
$qb->groupBy('c.id');
return $qb->getQuery()->getScalarResult();
or should I use nativeSQL instead?
any help would be appreciated,
thanks.
What are you trying to do is really interesting, because JOIN on a SELECT seems to not be supported by Doctrine2 with DQL or QueryBuilder. Of course, you can try with a native query.
However, to answer to your question, I believe that you don't need to make a JOIN on a SELECT. Simply, JOIN on StudentClasses and then add a condition in the WHERE about the $year! The WHERE clause is made for that.
You can use WITH clause to join entity with additional check, For your subquery you can write the same using left join with year filter, In join part i have used c.studentClasses based on the assumption that in Classes entity you have some mapped property for StudentClasses entity
$qb = $this->getEntityManager()
->getRepository('Classes')
->createQueryBuilder('c');
$qb->select('c.id AS id, c.name AS name, COUNT(s) AS studentCount');
$qb->leftJoin('c.studentClasses','sc2', 'WITH', 'sc2.year = :year');
$qb->leftJoin('sc2.students', 's');
$qb->setParameter('year', $inputYear);
$qb->groupBy('c.id');