Question

I want to perform a query which would look like this in native SQL:

SELECT
    AVG(t.column) AS average_value
FROM
    table t
WHERE
    YEAR(t.timestamp) = 2013 AND
    MONTH(t.timestamp) = 09 AND
    DAY(t.timestamp) = 16 AND
    t.somethingelse LIKE 'somethingelse'
GROUP BY
    t.somethingelse;

If I am trying to implement this in Doctrine's query builder like this:

$qb = $this->getDoctrine()->createQueryBuilder();
$qb->select('e.column AS average_value')
   ->from('MyBundle:MyEntity', 'e')
   ->where('YEAR(e.timestamp) = 2013')
   ->andWhere('MONTH(e.timestamp) = 09')
   ->andWhere('DAY(e.timestamp) = 16')
   ->andWhere('u.somethingelse LIKE somethingelse')
   ->groupBy('somethingelse');

I get the error exception

[Syntax Error] line 0, col 63: Error: Expected known function, got 'YEAR'

How can I implement my query with Doctrines query builder?

Notes:

  • I know about Doctrine's Native SQL. I've tried this, but it leads to the problem that my productive and my development database tables have different names. I want to work database agnostic, so this is no option.
  • Although I want to work db agnostic: FYI, I am using MySQL.
  • There is way to extend Doctrine to "learn" the YEAR() etc. statements, e.g. as seen here. But I am looking for a way to avoid including third party plugins.
Était-ce utile?

La solution

You can add Doctrine extension so you can use the MySql YEAR and MONTH statement by adding this configuration if you're on Symfony:

doctrine:
    orm:
        dql:
            string_functions:
                MONTH: DoctrineExtensions\Query\Mysql\Month
                YEAR: DoctrineExtensions\Query\Mysql\Year

now you can use the MONTH and YEAR statements in your DQL or querybuilder.

Note: The extension supports MySQL, Oracle, PostgreSQL and SQLite.

Autres conseils

In Symfony 4 you must install DoctrineExtensions:

composer require beberlei/DoctrineExtensions

And then edit the doctrine config file (config/packages/doctrine.yaml) as follow:

doctrine:
    orm:
        dql:
            string_functions:
                MONTH: DoctrineExtensions\Query\Mysql\Month
                YEAR: DoctrineExtensions\Query\Mysql\Year

orocrm/doctrine-extensions seems to be a good project too

It supports both MySQL and PostgreSql .. the goal is to be cross DB

For Symfony 4:

  1. Install: composer require beberlei/doctrineextensions
  2. Edit: config\packages\doctrine.yaml
    doctrine:
        orm:
            dql:
                datetime_functions:
                    DAY: DoctrineExtensions\Query\Mysql\Day
                    MONTH: DoctrineExtensions\Query\Mysql\Month
                    YEAR: DoctrineExtensions\Query\Mysql\Year
  1. Edit your controller:
    public function somex()
    {
        $em = $this->getDoctrine()->getManager();

        $emConfig = $em->getConfiguration();
        $emConfig->addCustomDatetimeFunction('YEAR', 'DoctrineExtensions\Query\Mysql\Year');
        $emConfig->addCustomDatetimeFunction('MONTH', 'DoctrineExtensions\Query\Mysql\Month');
        $emConfig->addCustomDatetimeFunction('DAY', 'DoctrineExtensions\Query\Mysql\Day');

        $day = '22';
        $month = '4';

        $qb = $em->createQueryBuilder()
            ->select('u')
            ->from('App\Entity\User', 'u')
            ->where('DAY(u.somedate) = :day')
            ->andwhere('MONTH(u.somedate) = :month')
            ->setParameter('month', $day)
            ->setParameter('day', $month)
        ;
        $trab = $qb->getQuery()->getResult();


        return $this->render('intranet/somex.html.twig', [
            'trab' => $trab
        ]);
    }
    ````

go to this page and choose your database systeme and pick up functions thats you want

... I too had the same problem as you... then I modified my doctrine.yaml file using exactly the same names as in the github file and it worked.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top