【问题标题】:symfony2: how to use group_concat in QueryBuildersymfony2:如何在 QueryBuilder 中使用 group_concat
【发布时间】:2012-06-01 12:33:28
【问题描述】:

我有一个名为“位置”的嵌套集(使用 Gedmo 树)实体。实体“Appartment”有 location_id,我需要做的是映射标量值,例如“path”来查询返回所有 appartments。

在 Doctrine1 中,我有这个代码:

/**
* Add "path" to each element
* 
* @param Doctrine_Query $query
* @param string $separator
*/
protected function addScalar_path(Doctrine_Query $query, $separator=", ")
{
    $subquery = "k99.root_id=o.root_id AND k99.lft<=o.lft AND k99.rgt>=o.rgt AND k99.level<=o.level" ;

    $query->addSelect("(SELECT GROUP_CONCAT(k99.name ORDER BY k99.level SEPARATOR '$separator') FROM Location k99 WHERE $subquery) AS path") ;
}

注意:“o”别名用于主查询。 这段代码可以让我使用

{foreach .... as $appartment}
   {$appartment->path}
...

哪个会打印:

Australia, Victoria, Melbourne, ...other children...

如何在 D2 中做同样的事情?以及如何在我的 symfony2 项目中包含学说扩展?

【问题讨论】:

标签: symfony doctrine-orm


【解决方案1】:

如果你想在 QueryBuilder 中使用它,你必须:

1) 添加DQL函数GroupConcat:GroupConcat

2 ) 注册 GroupConcat :DQL User Defined Functions

另一种选择是使用 NativeQuery :Native SQL


在 symfony2 中注册一个 DQL 函数非常简单,只需在 config.yml 中添加 GROUP_CONCAT,如下所示:

    entity_managers:
        default:
            dql:
                string_functions:
                    GROUP_CONCAT: YourBundle\Query\Mysql\GroupConcat

欲了解更多信息,请访问Registering Custom DQL Functions

【讨论】:

  • +1 用于原生 SQL。除此之外,对于没有经验的 Doctriners 来说,这仍然是最好的解决方案......
  • 我是一位非常有经验的 Doctrine1 用户,但 D2 正在杀死我。有我需要的示例代码吗?我还需要 QB 而不是 NativeQuery。以及如何在 Symfony2 项目中注册 GroupConcat?
  • 见上文我在Symfony2中添加了注册Group_Concat的方式,但是对于Native Query你可以查看官方示例,
  • 我试过你所说的关于 NativeSql 模式的方法,我之前已经使用过这个方法,但是现在直接在 phpmyadmin 中工作的相同查询,从学说 Native SQL 查询返回一个空数组... SELECT GROUP_CONCAT(id) FROM Products GROUP BY 类别、行、类型
  • 添加 GroupConcat 和注册的解决方案就像一个魅力。如果您使用 ORM(默认内容),则 config.yml 如下所示:教义 > orm > dql > string_functions > GROUP_CONCAT
【解决方案2】:

如果有人看到这篇文章,现在 Github 中有一个 Doctrine Extensions 存储库。回购中有关于如何使用它的说明。您可以使用 composer 安装它,然后使用您感兴趣的任何功能。

编辑:

为了用户 Tushar,在 Doctrine2 的 DQL 中使用 GROUP_CONCAT 的方法是简单安装Doctrine Extensions

composer require beberlei/DoctrineExtensions

要启用它:在 config.yml 中添加以下内容:

doctrine:
 orm:
     dql:
         string_functions:
             group_concat: DoctrineExtensions\Query\Mysql\GroupConcat

然后在您的代码中,您现在应该可以在 DQL 中使用 Group Concat:

$this->createQueryBuilder('location')
            ->select('location')
            ->addSelect("GROUP_CONCAT(DISTINCT location.name SEPARATOR '; ') AS locationNames");

        $result = $queryBuilder->getQuery()->getResult();

或者在原始问题的情况下:

$query->addSelect("(SELECT GROUP_CONCAT(k99.name ORDER BY k99.level SEPARATOR '$separator') FROM Location k99 WHERE $subquery) AS path");

【讨论】:

    【解决方案3】:

    只是对@a.aitboudad 答案的补充:
    链接的 DQL 函数 GroupConcat 似乎对 GROUP_CONCAT 有“有限支持”。
    这是完整的支持版本: 配置如他所说。

    // -------------------------------------------------
    // Complete support of GROUP_CONCAT in Doctrine2
    // -------------------------------------------------
    // Original Article: http://habrahabr.ru/post/181666/
    // Automated translation to English: http://sysmagazine.com/posts/181666/ 
    // Original github commit: https://github.com/denisvmedia/DoctrineExtensions/blob/d1caf21cd7c71cc557e60c26e9bf25323a194dd1/lib/DoctrineExtensions/Query/Mysql/GroupConcat.php
    
    /**
     * DoctrineExtensions Mysql Function Pack
     *
     * LICENSE
     *
     * This source file is subject to the new BSD license that is bundled
     * with this package in the file LICENSE.txt.
     * If you did not receive a copy of the license and are unable to
     * obtain it through the world-wide-web, please send an email
     * to kontakt@beberlei.de so I can send you a copy immediately.
     */
    
    namespace DoctrineExtensions\Query\Mysql;
    
    use Doctrine\ORM\Query\AST\Functions\FunctionNode,
        Doctrine\ORM\Query\Lexer;
    
    /**
     * Full support for:
     *
     * GROUP_CONCAT([DISTINCT] expr [,expr ...]
     *              [ORDER BY {unsigned_integer | col_name | expr}
     *                  [ASC | DESC] [,col_name ...]]
     *              [SEPARATOR str_val])
     *
     */
    class GroupConcat extends FunctionNode
    {
        public $isDistinct = false;
        public $pathExp = null;
        public $separator = null;
        public $orderBy = null;
    
        public function parse(\Doctrine\ORM\Query\Parser $parser)
        {
            $parser->match(Lexer::T_IDENTIFIER);
            $parser->match(Lexer::T_OPEN_PARENTHESIS);
    
            $lexer = $parser->getLexer();
            if ($lexer->isNextToken(Lexer::T_DISTINCT)) {
                $parser->match(Lexer::T_DISTINCT);
    
                $this->isDistinct = true;
            }
    
            // first Path Expression is mandatory
            $this->pathExp = array();
            $this->pathExp[] = $parser->SingleValuedPathExpression();
    
            while ($lexer->isNextToken(Lexer::T_COMMA)) {
                $parser->match(Lexer::T_COMMA);
                $this->pathExp[] = $parser->StringPrimary();
            }
    
            if ($lexer->isNextToken(Lexer::T_ORDER)) {
                $this->orderBy = $parser->OrderByClause();
            }
    
            if ($lexer->isNextToken(Lexer::T_IDENTIFIER)) {
                if (strtolower($lexer->lookahead['value']) !== 'separator') {
                    $parser->syntaxError('separator');
                }
                $parser->match(Lexer::T_IDENTIFIER);
    
                $this->separator = $parser->StringPrimary();
            }
    
            $parser->match(Lexer::T_CLOSE_PARENTHESIS);
        }
    
        public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
        {
            $result = 'GROUP_CONCAT(' . ($this->isDistinct ? 'DISTINCT ' : '');
    
            $fields = array();
            foreach ($this->pathExp as $pathExp) {
                $fields[] = $pathExp->dispatch($sqlWalker);
            }
    
            $result .= sprintf('%s', implode(', ', $fields));
    
            if ($this->orderBy) {
                $result .= ' ' . $sqlWalker->walkOrderByClause($this->orderBy);
            }
    
            if ($this->separator) {
                $result .= ' SEPARATOR ' . $sqlWalker->walkStringPrimary($this->separator);
            }
    
            $result .= ')';
    
            return $result;
        }
    
    }
    
    // -------------------------------------------------
    // Example of usage:
    // -------------------------------------------------
    $query = $this->createQueryBuilder('c')
        ->select("
                c as company,
                GroupConcat(b.id, ';', b.headOffice, ';', b.city, ';', s.name
                ORDER by b.id
                SEPARATOR '|') AS branches
            ")->leftJoin('c.branches', 'b')
        ->leftJoin('b.country', 's')
        ->groupBy('c.id')
        ->setFirstResult(0)
        ->setMaxResults(10)
        ->getQuery();
    $result = $query->getResult();
    

    【讨论】:

    • 这是在查询中使用 mysql 函数的最可怕的方式。为什么学说2限制直接使用mysql函数。
    • 他们盗用了我自己写的这个功能,请把学分改成这个:habrahabr.ru/post/181666(sysmagazine.com好像做了我文章的自动翻译)。
    • @StepanYudin : 实际上在第 2 行提到了:“原文:habrahabr.ru/post/181666
    【解决方案4】:

    我有类似的问题。 GROUP_CONCAT 不允许在里面使用 CASE-WHEN。 This library 解决了我的问题,所以也许会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-13
      • 2016-06-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多