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
Related
I have a doctrine statement to get all the fields from a table
->createQueryBuilder()
->select('u')
->from(User::class, 'u')
How can I add to this select an additional column based on a value in another column? This would be the mysql equivalent:
SELECT
u.*,
IF(u.group = 1, 'Yes', 'No') as isAdmin
FROM user u ...
I need to know how to do this in doctrine. Thanks.
I have the following fields in one of my entities: price(decimal), promo(boolean), and promoPrice(decimal) and I want to get query with order by real price, so I need to create query like this one:
SELECT *, (!promo*price + promo*promo_price) as real_price
FROM `product` ORDER BY real_price ASC
Is there any way to do it with QueryBuilder or maybe I need to use some native methods?
SOLUTION:
$repository = $this->getDoctrine()->getRepository('AppBundle:Product');
$query = $repository->createQueryBuilder('p')
->addSelect('CASE WHEN p.promo = :value THEN p.promoPrice ELSE p.price END AS HIDDEN realPrice')
->setParameter('value', true)
->orderBy('realPrice', 'ASC')
->getQuery();
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');
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.
I am developing a web application in symfony. I want to fetch the records from database according to months. My Query is:
$totalSearchesByAdminAll = $em->createQueryBuilder()
->select('count(SearchHistory.id) AS totalSearchesByAdmin')
->from('DRPAdminBundle:Log', 'SearchHistory')
->where('SearchHistory.last_updated like :last_updated')
->setParameter('last_updated',??????.'%')
->andwhere('SearchHistory.event = :event')
->setParameter('event','ADMIN_SEARCH')
->getQuery()
->getArrayResult();
last_updated is datetime field and stores in database like:
2015-06-12 11:50:44
I want records like
Jan=>5
Feb=>10
.....and so on..
Please Help
You can group your data by month and year with a DATE_FORMAT mysql statement.
In order to use the mysql function in a DQL Doctrine statement i suggest you to install the mapado/mysql-doctrine-functions doctrine function.
Simply add to your composer.json and enable it in the config.yml as follow:
#app/config/config.yml
orm:
auto_generate_proxy_classes: %kernel.debug%
entity_managers:
default:
mappings:
....
dql:
datetime_functions:
date_format: Mapado\MysqlDoctrineFunctions\DQL\MysqlDateFormat
Then you can use in the repository as example:
$qb = $this->createQueryBuilder('p')
->select("DISTINCT DATE_FORMAT(p. last_updated,'%m-%Y') as formatted_date")
->andwhere('p.SearchHistory.event = :event')
->setParameter('event','ADMIN_SEARCH')
->addGroupBy("formatted_date")
->orderBy('p.last_updated')
->getQuery()
->getResult();
You need to modify the example to add the count
Hope this help.
base query:
select count(last_updated), month(last_updated) from TABLENAME group by month(last_updated)
You can group by month in SQL:
$totalSearchesByAdminAll = $em->createQueryBuilder()
->select('count(SearchHistory.id) AS totalSearchesByAdmin')
->addSelect('MONTH(last_updated) AS month')
->from('DRPAdminBundle:Log', 'SearchHistory')
->where('SearchHistory.last_updated >= :last_updated')
->setParameter('last_updated','2015-06-12 11:50:44')
->andwhere('SearchHistory.event = :event')
->setParameter('event','ADMIN_SEARCH')
->groupBy('month')
->getQuery()
->getArrayResult();
dont forget to add in your doctrine configuration:
doctrine:
orm:
dql:
string_functions:
MONTH: DoctrineExtensions\Query\Mysql\Month