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中找到任何关于窗口函数的文档,这本身是在doctrine中支持还是我必须为此创建自定义dql函数?
答案 0 :(得分:3)
Doctrine中不支持此供应商特定功能。创建自定义DQL函数或使用Native SQL。
答案 1 :(得分:1)
根据其中一项评论中的要求,我为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)');
希望它可以帮助某人。
答案 2 :(得分:0)
窗口函数类的版本略有不同。它更通用,因为您可以在此处使用任何聚合函数+在窗口中使用“ 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')
答案 3 :(得分:0)
这里是扩展,在教义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