the goal of this query is to show records from table orders that don't have any shipments created yet. Here is how it should be done in SQL:
SELECT *
FROM orders
LEFT JOIN orders_shipments shipments ON orders.trx_id = shipments.trx_id
WHERE shipments.shipment_id IS NULL
AND orders.purchase_date IS NOT NULL
AND orders.fulfillment_channel = 'MFN';
The following query shows 0 results. Vs the following:
$qb = $this->createQueryBuilder('orders');
$qb->select('orders, shipments')
->leftjoin('orders.shipments', 'shipments')
->Where('shipments.id IS NULL')
->ANDWhere('orders.purchaseDate IS NOT NULL')
->ANDWhere('orders.fulfillmentChannel = :a')->setParameter('a', 'MFN');;
$results = $qb->getQuery()
->getResult();
return $results;
Does show results. Why is that and how to fix it?
Not sure why but I had to use GROUP and HAVING to get it to work:
$qb = $this->createQueryBuilder('orders');
$qb->select('orders, shipments')
->leftjoin('orders.shipments', 'shipments')
->Where('shipments.id IS NULL')
->ANDWhere('orders.purchaseDate IS NOT NULL')
->ANDWhere('orders.fulfillmentChannel = :a')->setParameter('a', 'MFN')
->GroupBy('orders.id')
->having('count(shipments) = 0');
$results = $qb->getQuery()->getResult();
Related
I have method findByTag() which should return entites with %#i% but it won't. This is sql which dql builded:
SELECT p0_.id AS id_0, p0_.content AS content_1, p0_.date AS date_2, p0_.user_id AS user_id_3 FROM post p0_ INNER JOIN user u1_ ON p0_.user_id = u1_.id LEFT JOIN points p2_ ON p0_.id = p2_.post_id LEFT JOIN comments c3_ ON p0_.id = c3_.post_id WHERE p0_.content LIKE '%#i%' ORDER BY p0_.date DESC LIMIT 20 if i enter it to mysql it return it ok.
Anybody have an idea?
$dql = $this->createQueryBuilder('p')
->innerJoin('p.user', 'c')
->leftJoin('p.points', 'pp')
->leftJoin('p.comments', 'cc')
->Where('p.content LIKE \'%#i%\'')
->setMaxResults($max)
->orderBy('p.date','DESC');
$dql->getQuery()
->getResult();
return $dql;
try it
$dql = $this->createQueryBuilder()
->from('YourBundleName:YourEntityName', 'p')
->innerJoin('YourBundleName.user', 'c')
->leftJoin('YourBundleName.points', 'pp')
->leftJoin('YourBundleName.comments', 'cc')
->Where('p.content LIKE \'%#i%\'')
->setMaxResults($max)
->orderBy('p.date','DESC');
return $dql->getQuery()->getResult();
I realized this sql which works without problems
SELECT meeting.name, meeting.date, community.name, participation.isPresent, participation.user_id
FROM meeting
INNER JOIN community
ON meeting.community_id = community.id
AND community.is_active = 1
LEFT join participation
ON meeting.id = participation.meeting_id
AND participation.user_id = 1078
WHERE meeting.date >= CURRENT_DATE()
ORDER BY meeting.date DESC
I'm trying to reproduce it with the doctrine query builder but I never got the right result. The user id part doesn't seem to be part of the leftJoin function but is applied to the request globally, which is not what I want.
public function getNextMeetings()
{
$qb = $this->createQueryBuilder('m')
->select('m.name AS meeting, m.date, c.name AS community, p.isPresent', 'IDENTITY(p.user) AS user')
->innerJoin('m.community', 'c')
->where('c.isActive = true')
->leftJoin('m.participations', 'p')
//->leftJoin('p.user', 'u')
//->where('u.id = 1078 OR u.id IS NULL')
//->where('IDENTITY(p.user) = 1078')
->andWhere('m.date >= CURRENT_DATE()')
->orderBy('m.date', 'DESC');
return $qb->getQuery()->execute();
}
My comments are what I tried to fix this issue.
Check Working with QueryBuilder: High level API methods
More precisely, the definition od leftJoin() function:
public function leftJoin($join, $alias, $conditionType = null, $condition = null, $indexBy = null);
You can place a condition on the joined Entity by:
use Doctrine\ORM\Query\Expr;
->leftJoin('m.participations', 'p', Expr\Join::WITH, 'p.user = :userId')
->setParameter('userId', 1078)
Note you do not need a condition for "meeting.id = participation.meeting_id", as this is autoapplied by the relation m.participations to the join constructed.
My colons are never transformed into the parameters value
$queryBuilder
->select('p.id', 'p.quantite', 'p.dateAjoutPanier', 'p.prix, p.user_id', 'v.nom', 'p.produit_id')
->from('paniers', 'p')
->innerJoin('p', 'produits', 'v', 'p.produit_id=v.id')
->where('p.user_id = :userid')
->andWhere('p.produit_id = :produitid')
->setParameter('produitid',(int)1)
->setParameter('userid',(int)1);
return $queryBuilder->getSQL();
this code return :
SELECT p.id, p.quantite, p.dateAjoutPanier, p.prix, p.user_id, v.nom, p.produit_id FROM paniers p INNER JOIN produits v ON p.produit_id=v.id WHERE (p.user_id = :userid) AND (p.produit_id = :produitid)
Someone have the problem (or the solution) ?
If you have selected more than one rows you should use the loop to iterate over each key - value entity.
But if you have only one row, use getSingleResult() or getOneOrNullResult() methods with setMaxResults(1)
For example:
$queryBuilder
->select('p.id', 'p.quantite', 'p.dateAjoutPanier', 'p.prix, p.user_id', 'v.nom', 'p.produit_id')
->from('paniers', 'p')
->innerJoin('p', 'produits', 'v', 'p.produit_id=v.id')
->where('p.user_id = :userid')
->andWhere('p.produit_id = :produitid')
->setParameter('produitid',1)
->setParameter('userid',1)
->setMaxResults(1)
->getQuery()
->getOneOrNullResult();
I would like to know how can I set limit on 1 query and then query based on the selected results.
For example I want to select the last 100 posts and the do some operation.
$first_query= $this->getEntityManager()
->createQuery(
'SELECT p FROM TestBundle:Post p ORDER BY p.date DESC'
)
->setMaxResults(5);
How to use this result to select from it in the next query?
return $this->getEntityManager()
->createQuery(
"SELECT u.username , max(p.date),d.points,l.name
FROM $first_query
JOIN p.location l JOIN p.user u JOIN u.deeds d
WHERE l.name = :location
GROUP BY u.id
ORDER BY d.points DESC , p.date DESC
"
)
->setParameter('location' , $location)
->getResult();
I found out that DQL doesn't support limits so I went for native sql.
$stmt = $this->getEntityManager()->getConnection()->prepare($query);
$stmt->execute();
return $stmt->fetchAll();
This way you can do whatever you want with the $query varaible you can set limits and everythign as it's a normal sql statement.
I want to produce a DQL for following MySQL query:
SELECT * FROM `folders` AS `t` WHERE `t`.`Library` = #myLib AND AND `t`.`Id` NOT IN (
SELECT DISTINCT(`f`.`Id`) FROM `folders` AS `f` JOIN `folders` AS `ff` ON (`f`.`Position` LIKE CONCAT(`ff`.`Position`, '%')) WHERE `ff`.`Active` = 1 AND `ff`.`Library` = #myLib AND `f`.`Library` = #myLib
)
ORDER BY `t`.`Position` ASC
The query works fine in mySQL and returns correct records.
To generate DQL I've tried both below options:
1.
$query = $em->createQuery("SELECT F FROM MyBundle:Folders T WHERE T.Library = :libid AND T.id NOT IN (
SELECT DISTINCT(F.id) FROM MyBundle:Folders F JOIN MyBundle:Folders FF WITH F.Position LIKE CONCAT(FF.Position, '%') AND F.Library = :libid AND FF.Library = :libid AND FF.Active = true
) ORDER BY T.Position ASC")
->setParameter('libid', $library);
$result = $query->getResult();
2.
$q1 = $this->createQueryBuilder('F')
->select('DISTINCT(F.id)');
$q1->join('\MyBundle\Entity\Folders', 'FF', 'WITH', $q1->expr()->like('F.Position', $q1->expr()->literal('CONCAT(FF.Position, \'%\')')))
->where('FF.Active = true')
->andWhere("FF.Library = '$library'")
->andWhere("F.Library = '$library'");
$q2 = $this->createQueryBuilder('T');
$q2->where('T.Library = :libid')
->andWhere($q2->expr()->notIn('T.id', $q1->getDQL()))
->setParameter('libid', $library)
->orderBy('T.Position', 'ASC');
$result = $q2->getQuery()->getResult();
In my perspective it seems OK but I don't know why in both ways it produce following exception:
ContextErrorException: Warning: Illegal offset type in
/var/www/Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Query/SqlWalker.php line 601
Any help will be appreciated.
It seems no one has an answer for this. I found a temporary solution as below (I call it temporary because I'm changing my unique query to two separate queries and it seems the issue is in core of doctrine).
$qb = $this->createQueryBuilder('F')
->select('DISTINCT(F.id)');
$qb->join('\MyBundle\Entity\Folders', 'FF', 'WITH', 'F.Position LIKE CONCAT(FF.Position, \'%\')')
->where('FF.Active = true')
->andWhere("FF.Library = :library")
->andWhere("F.Library = :library")
->setParameter('library', $library);
$included_folders = $qb->getQuery()->getArrayResult();
$query = $this->createQueryBuilder('F')
->where('F.Active = false')
->andWhere('F.Library = :library')
->setParameter('library', $library)
->orderBy('F.Position', 'ASC');
if (!empty($included_folders)) {
if (count($included_folders) > 1)
{
foreach ($included_folders as $index => $value)
{
if (is_array($value))
{
$included_folders[$index] = !empty($value['id']) ? $value['id'] : $value[1];
}
}
$query->andWhere($query->expr()->notIn('F.id', $included_folders));
}
else {
$query->andWhere('F.id != :folder ')
->setParameter('folder', $included_folders[0]);
}
}
$result = $query->getQuery()->getResult();
As you see instead of getting the dql from my first query and putting it inside my second dql in notIn section which will lead to the warning message, I execute the first query and get the results then put the results inside notIn if amount of returned values are more than one, otherwise it should be in regular !=. This solved my problem for now, but as you see amount of transactions are now increased
If anyone has a better solution or any fix for the warning I will be thankful.
I've encountered the same error and it seems that this has been fixed in latest trunk of Doctrine/ORM.
Using "2.5.*#dev" as version in your composer.json for doctrine/orm should fix this bug and will let you do what you want in a single query.