Can I use window functions in doctrine 2?

跟風遠走 提交于 2019-12-05 10:26:20

There is no support for this vendor specific function in Doctrine. Either create a custom DQL function or use Native SQL.

As asked in one of the comments, I attach my custom string function for COUNT() OVER()

<?php

namespace Example\Doctrine\CustomFunctions;

use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;

/**
 * Class CountOverSql
 */
class CountOverSql extends FunctionNode
{
    /**
     * @var string
     */
    private $field;

    public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
    {
        return "COUNT(".$this->field->dispatch($sqlWalker).") OVER()";
    }

    public function parse(\Doctrine\ORM\Query\Parser $parser): void
    {
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);
        $this->field = $parser->StringPrimary();
        $parser->match(Lexer::T_CLOSE_PARENTHESIS);
    }
}

and you only need to add this code to your doctrine configuration:

$entityManager->getConfiguration()->addCustomStringFunction('count_over', function ($name) use ($c) {
    return new Example\Doctrine\CustomFunctions\CountOverSql($name);
});

And to use it, add this code to your select statement:

$queryBuilder->select('table_name', 'count_over(table_name.id)');

Hope it helps someone.

Slightly different version of window function class. It's more universal, because you can use here any aggregate function + use "Order By" clause in window.

use Doctrine\ORM\Query\AST\AggregateExpression;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\AST\OrderByClause;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;

class Over extends FunctionNode
{
    /** @var AggregateExpression */
    private $functionExpr;

    /** @var OrderByClause */
    private $orderByExpr;

    /**
     * {@inheritdoc}
     *
     * @throws \Doctrine\ORM\Query\AST\ASTException
     */
    public function getSql(SqlWalker $sqlWalker): string
    {
        if (!empty($this->orderByExpr->orderByItems)) {
            return "{$this->functionExpr->dispatch($sqlWalker)} OVER ({$this->orderByExpr->dispatch($sqlWalker)})";
        }

        return "{$this->functionExpr->dispatch($sqlWalker)} OVER ()";
    }

    /**
     * @param Parser $parser
     *
     * @throws \Doctrine\ORM\Query\QueryException
     */
    public function parse(Parser $parser): void
    {
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);
        $this->functionExpr = $parser->StringPrimary();
        $parser->match(Lexer::T_COMMA);
        $this->orderByExpr = $parser->OrderByClause();
        $parser->match(Lexer::T_CLOSE_PARENTHESIS);
    }
}

And use it like this:

$aggregateQueryResult = $this->createQueryBuilder('agg')
      ->select('OVER(sum(agg.quantity), ORDER BY agg.date, agg.id) as aggregated_sum')
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!