I can't find an example of DQL, here's what the semi-pseudocode would look like:
Bring back invoices
- Where company id = 5
AND
(
->where('DATE(i.startPeriod) BETWEEN :startDate AND :endDate')
->orWhere('DATE(i.endPeriod) BETWEEN :startDate AND :endDate')
->orWhere(':startDate BETWEEN DATE(i.startPeriod) and DATE(i.endPeriod)')
->orWhere(':endDate BETWEEN DATE(i.startPeriod) and DATE(i.endPeriod)')
)
So you have four OR's nested within one encapsulating AND.
Does anyone know how to do that with Doctrine DQL? Nest a bunch of OR's within one giant AND?
You would need to use the Expr() class with the query builder.
// $qb instanceof QueryBuilder
$qb->select('i')
->from('invoices', 'i')
->where('c.id = :cid')
->andWhere($qb->expr()->orX(
$qb->expr()->between('i.startPeriod',':startdate',':enddate'),
$qb->expr()->between('i.endPeriod',':startdate',':enddate'),
...
You can read more about the Expr() class in the documentation.
EDIT:
Just realized your initial question asked specifically about DQL. You can use parens in DQL to group things, so something like this.
$query = $em->createQuery(
'SELECT i FROM Invoices i
WHERE c.id = :id
AND (
(i.startPeriod BETWEEN :startDate AND :endDate)
OR
(i.endPeriod BETWEEN :startDate AND :endDate)
OR
(:startDate BETWEEN i.startPeriod AND i.endPeriod)
OR
(:endDate BETWEEN i.startPeriod AND i.endPeriod)
) JOIN i.company c');
Related
i'm new with doctrine and want to make a query on my db using it
SELECT DATE_FORMAT(DATE(created_at), '%m-%Y') AS 'date',
COUNT(DISTINCT(id)) AS 'value'
FROM users
GROUP BY YEAR(DATE(created_at)), MONTH(DATE(created_at))
i read some documentation but still have few questions
how to i select multiple elements; give aliases to my selected elements, do a left join. Are WEEK() MONTH() and YEAR() functions avaible ? does DATE_FORMAT (from mysql) is avaible ?
thank you
I believe you should use the query builder (http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/query-builder.html).
Considering date, you can use symfony datetime objects and format them.
For left join the leftJoin method can be used (http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/query-builder.html)
<?php
// $qb instanceof QueryBuilder
$qb->select('u as aliasName') //see for alias
->from('User', 'u')
->leftJoin('u', 'phonenumbers', 'p', 'u.id = p.user_id') //see for left join
->where('u.id = ?1')
->addwhere(u.date < :date)
->orderBy('u.name', 'ASC')
->setParameter('date', $symfonyDateTime->format('Y-m-d')); //see for date
Instead of QueryBuilder, you can also try DQL (http://symfony.com/doc/current/doctrine.html and http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html):
$em = $this->getDoctrine()->getManager();
$query = $em->createQuery(
'SELECT p
FROM AppBundle:Product p
WHERE p.price > :price
ORDER BY p.price ASC'
)
->setParameter('price', 19.99);
$products = $query->getResult();
You could install doctrine extensions in order to use functions like:
DATE, MINUTE, HOUR, DAY, WEEK and many more.
Example:
Doctrine Configuration
doctrine:
dbal:
....
orm:
auto_generate_proxy_classes: "%kernel.debug%"
entity_managers:
default:
dql:
datetime_functions:
DATE_FORMAT: DoctrineExtensions\Query\Mysql\DATE_FORMAT
Then you can really easy add alias like this:
DATE_FORMAT(s.createdAt,'%Y-%m-01') as date
How can I convert below query to Doctrine:
SELECT restaurants.restaurant_name ,
restaurants.restaurant_id,
j.LASTPRICE
FROM restaurants
LEFT JOIN
(
SELECT f.food_id AS fid,
f.restaurants_restaurant_id AS rid,
Max(f.food_last_price) AS LASTPRICE
FROM foods AS f
LEFT JOIN restaurants AS r
ON r.restaurant_id = f.restaurants_restaurant_id
WHERE f.food_last_price IS NOT NULL
GROUP BY r.restaurant_id) j
ON restaurants.restaurant_id = j.rid
Here is my code:
$qb = $this->_em->createQueryBuilder();
$qb2 = $this->_em->createQueryBuilder();
$getMaxPercentage = $qb2
->select(
'MAX (Food.foodLastPrice) AS LASTPRICE ',
'Food.foodId AS fId',
'Food.restaurantsRestaurantId AS rID'
)
->from($this->entityClass,'Restaurant')
->innerJoin('Restaurant.foods','Food')
->where('Food.foodLastPrice IS NOT NULL')
->groupBy('Restaurant.restaurantId')
->getDQL();
$restaurantList = $qb
->select('Restaurants.restaurantName, Restaurants.restaurantId , j.LASTPRICE')
->from($this->entityClass,'Restaurants')
->leftJoin($getMaxPercentage,'j','WITH','Restaurants.restaurantId = j.rID')
->getQuery()->execute();
dd($restaurantList);
I give an error :
SELECT Restaurants.restaurantName,': Error: Class 'SELECT' is not defined.
I've already known I could set sub queries in main query, Although in this case I does not want to use sub query in Where expression. Any suggestion for using select in LeftJoin in doctrine?
EDITED : I've tried to use DQL in my query:
$query = $this->_em->createQuery(
'
SELECT Restaurants.restaurantName , Restaurants.restaurantId
FROM App\\Restaurant AS Restaurants
LEFT JOIN (
SELECT f.foodId AS fid,
f.restaurantsRestaurantId AS rid,
Max(f.foodLastPrice) AS LASTPRICE
FROM App\\Food AS f
LEFT JOIN App\\Restaurant AS r
WITH r.restaurantId = f.restaurantsRestaurantId
GROUP BY r.restaurantId) AS J
ON Restaurants.restaurantId = j.rid
');
But I gave an another error :
[Semantical Error] Error: Class '(' is not defined.
Is it possible to use select in left join in Doctrine?
EDITED 2 : I read a similar question and I've decided to write in another way :
$qb = $this->_em->createQueryBuilder();
$qb2 = $this->_em->createQueryBuilder();
$subSelect = $qb2
->select(
array(
'Food.foodLastPrice AS LASTPRICE ',
'Food.foodId AS fId',
'Food.restaurantsRestaurantId AS rId')
)
->from($this->entityClass,'Restaurant')
->innerJoin('Restaurant.foods','Food')
->where('Food.foodLastPrice IS NOT NULL')
->groupBy('Restaurant.restaurantId')
->getQuery()->getSQL();
$restaurantList =
$qb->select(
'Restaurant1'
)
->from($this->entityClass, 'Restaurant1')
->leftJoin('Restaurant1',sprintf('(%s)',$subSelect),'internalQuery','Restaurant1.restaurantId = internalQuery.rId')
->getQuery()->getSQL();
dd($restaurantList);
Again, I got an error:
near 'Restaurant1 (SELECT': Error: Class 'Restaurant1' is not defined.
What you're trying to do is impossible :
https://github.com/doctrine/doctrine2/issues/3542 (november 2013, but doctrine concept didn't change since and doctrinebot closed this on 7 Dec 2015)
DQL is about querying objects. Supporting subselects in the FROM
clause means that the DQL parser is not able to build the result set
mapping anymore (as the fields returned by the subquery may not match
the object anymore). This is why it cannot be supported (supporting it
only for the case you run the query without the hydration is a no-go
IMO as it would mean that the query parsing needs to be dependant of
the execution mode).
In your case, the best solution is probably to run a SQL query instead
(as you are getting a scalar, you don't need the ORM hydration anyway)
You can find workarounds like raw sql, or rethinking your query.
Could somebody convert this query for me in querybuilder?
SELECT m.id,n.unitid
FROM mappaths m JOIN unitids n on (m.id=n.id) where n.databaseid=1
I am using this query but it gives me all the values of mm.unitid, while my requirement is to get only one value that is defined by test=1 variable
$query=$qb->select('mm.unitid')
->from('ApiMapBundle:Mappaths','m')
->from('ApiMapBundle:Unitids','mm')
// ->leftJoin('m','u')
->leftJoin('m.refUnitids1','u','WITH','m.id = u')
// ->leftJoin('m.refUnitids2','v')
->where('m.id=:test')
->setParameter('test',1)
->getQuery()->getResult();
Try following:
$query = $qb->select('mm.unitid')
->from('ApiMapBundle:Mappaths','m')
->innerJoin('m.refUnitids1','mm','WITH','m.id = mm.FIELD') //you need to specify on which field of mm join should be done
->where('m.id=:test')
->setParameter('test',1)
->getQuery()
->getResult();
You need to specify field of Unitids which should be used to join to Mappaths. The best way would be to define this relation in Entity definition, then you can use just ->innerJoin('m.refUnitids1','mm') without additional join parameters.
Also, in this case, it is better to use innerJoin instead of leftJoin
I'm wondering what exactly are the pros of using doctrine to build queries such as :
<?php
// $qb instanceof QueryBuilder
$qb->select('u')
->from('User u')
->where('u.id = :identifier')
->orderBy('u.name ASC');
->setParameter('identifier', 100); // Sets :identifier to 100, and thus we will fetch a user with u.id = 100
The only advantage i see here is data sanitizing and parameter binding, which can be easily done using PDO.
Also another example :
<?php
// $qb instanceof QueryBuilder
// example8: QueryBuilder port of: "SELECT u FROM User u WHERE u.id = ? OR u.nickname LIKE ? ORDER BY u.surname DESC" using Expr class
$qb->add('select', new Expr\Select(array('u')))
->add('from', new Expr\From('User', 'u'))
->add('where', $qb->expr()->orX(
$qb->expr()->eq('u.id', '?1'),
$qb->expr()->like('u.nickname', '?2')
))
->add('orderBy', new Expr\OrderBy('u.name', 'ASC'));
Is it really worth the extra dependencies are performance cost ? The above syntax seems more complicated to me than a simple string containing the query.
It is more structural this way. It also removes DQL(or SQL) code from the PHP code that looks much better this way.
This is the current query that I have, and it works fine:
$q = $this->_em->createQuery("SELECT s FROM app\models\Sub s
LEFT JOIN s.case c
WHERE s.type LIKE '%$type'
AND c.id = '$id'");
foreach ($q->getResult() as $row) {
$results[$row->getId()] = $row;
}
I want to convert this to the QueryBuilder API structure, this is what I have so far, but it's not working correctly. (And I need the results as the same format as above).
$q = $this->_em->createQueryBuilder();
$q->add('select', 's')
->add('from', 'app\models\Sub s')
->add('leftJoin', 's.case c')
->add('where', 's.type LIKE :type')
->add('where', 'c.id = :case');
->setParameter('type', "%$type");
->setParameter('case', $id);
And again, this isn't working properly, and I don't know how to get the results in the same format as above. Thanks!
Close, but no cigar. You'll need to learn how to use the Expr classes that comes with Doctrine in order to create the correct WHERE clause.
http://www.doctrine-project.org/docs/orm/2.1/en/reference/query-builder.html#expr-classes
In the example you provided, you are actually aiming for something like this (not tested):
$q->add('select', 's')
->add('from', 'app\model\Sub s')
->add('leftJoin', 's.case c')
->add('where', $q->expr()->andX($q->expr()->like('s.type', ':type'), $q->expr()->eq('case', ':case')))
->setParameter('type', "%$type")
->setParameter('case', $id);
As your WHERE clause gets more complicated, so will the nesting of expressions.