5
SELECT invoice.id, 
COUNT(slip.id),
SUM(projected_minutes)  OVER (PARTITION BY task.id) AS projected_minutes
FROM invoice
INNER JOIN task ON task.invoice_id = invoice.id
LEFT JOIN slip ON slip.task_id = task.id

上面的查询在 postgresql 中,我想将其转换为 DQL,但我在 DQL 中找不到任何关于窗口函数的文档,这是在教义中本机支持的,还是我必须为此创建一个自定义 dql 函数?

4

4 回答 4

4

Doctrine 中不支持此供应商特定功能。创建自定义 DQL 函数或使用本机 SQL。

于 2013-03-26T20:39:07.017 回答
2

正如其中一条评论所要求的,我为 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);
    }
}

您只需将此代码添加到您的学说配置中:

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

要使用它,请将此代码添加到您的 select 语句中:

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

希望它可以帮助某人。

于 2018-12-03T11:57:16.080 回答
1

窗口函数类的版本略有不同。它更通用,因为您可以在这里使用任何聚合函数 + 在 window.properties 中使用“Order By”子句。

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);
    }
}

并像这样使用它:

$aggregateQueryResult = $this->createQueryBuilder('agg')
      ->select('OVER(sum(agg.quantity), ORDER BY agg.date, agg.id) as aggregated_sum')
于 2019-03-21T19:19:05.027 回答
0

这是在 Doctrine 2 https://github.com/elshafey/doctrine-window-functions中提供寡妇函数功能的扩展

您可以按以下方式使用扩展程序

// configure the extension first
$entityManager->getConfiguration()->addCustomStringFunction(
    'WINDOW',
    \Elshafey\DoctrineExtensions\WindowFunctions\Query\Mysql\Window::class
);

// use your window function formula
SELECT invoice.id, 
COUNT(slip.id),
WINDOW(SUM(projected_minutes))  OVER (PARTITION BY task.id) AS projected_minutes
FROM invoice
INNER JOIN task ON task.invoice_id = invoice.id
LEFT JOIN slip ON slip.task_id = task.id
于 2020-09-19T23:52:01.770 回答