【问题标题】:Can I use window functions in doctrine 2?我可以在学说 2 中使用窗口函数吗?
【发布时间】:2013-03-16 19:54:19
【问题描述】:
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 函数?

【问题讨论】:

    标签: postgresql symfony doctrine-orm window-functions


    【解决方案1】:

    这是一个在 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
    

    【讨论】:

      【解决方案2】:

      窗口函数类的版本略有不同。它更通用,因为您可以在这里使用任何聚合函数 + 在窗口中使用“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】:

        根据其中一个 cmets 的要求,我为 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);
        });
        

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

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

        希望对某人有所帮助。

        【讨论】:

          【解决方案4】:

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

          【讨论】:

          • 怕这个,想找这个自定义的DQL函数,结果空了,猜我会写,就是不想重新发明轮子。
          • OVER 并不完全是特定于供应商的,除非“特定于供应商”的意思是“MySQL 不理解的标准 SQL”。
          • @muistooshort 让我重新表述一下:“供应商之间的最小公分母”——看起来更好,不是吗?
          • 窗口函数是 SQL 的一部分;)
          • 来到这里寻找同样的东西。如果有人编写了此自定义 DQL,它将节省工作。
          猜你喜欢
          • 2017-03-28
          • 2017-02-06
          • 2015-12-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-12
          相关资源
          最近更新 更多