symfony2: how to use group_concat in QueryBuilder

后端 未结 4 663
眼角桃花
眼角桃花 2020-12-01 09:11

I am having nested-set (using Gedmo tree) entity called \"Location\". Entity \"Appartment\" has location_id and what I need to do it to map scalar value called eg \"path\" t

相关标签:
4条回答
  • 2020-12-01 09:53

    I had similar problem. GROUP_CONCAT does not allow using CASE-WHEN inside. This library fixed my issues, so maybe it will be helpful.

    0 讨论(0)
  • 2020-12-01 09:57

    If you want to use it in QueryBuilder you must :

    1) add DQL functions GroupConcat: GroupConcat

    2 ) Registering GroupConcat :DQL User Defined Functions

    another alternative is to use NativeQuery :Native SQL


    In symfony2 registering a function DQL it's very simple just add GROUP_CONCAT in config.yml like:

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

    For more information visit Registering Custom DQL Functions

    0 讨论(0)
  • 2020-12-01 10:03

    Just an addition to @a.aitboudad's answer:
    The DQL function GroupConcat linked appears to have a «limited support for GROUP_CONCAT».
    Here is the full support version : The configuration is as he mentioned.

    // -------------------------------------------------
    // 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();
    
    0 讨论(0)
  • 2020-12-01 10:06

    If any comes across this post, there's now a Doctrine Extensions repository in Github. The repo has instructions on how to use it. You can use composer to install it and then use any function you're interested in.

    EDIT:

    For the Sake of the user Tushar, the way to use GROUP_CONCAT in Doctrine2's DQL is simple install Doctrine Extensions:

    composer require beberlei/DoctrineExtensions
    

    To enable it: add the following in your config.yml:

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

    Then in your code, you should be able now to use Group Concat in your DQLs:

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

    Or in the case for the original question:

    $query->addSelect("(SELECT GROUP_CONCAT(k99.name ORDER BY k99.level SEPARATOR '$separator') FROM Location k99 WHERE $subquery) AS path");
    
    0 讨论(0)
提交回复
热议问题