Doctrine2 和 group_concat

4

我一直在浏览文档和谷歌,但没有找到解决方案。

在doctrine2(DQL)中,有没有办法执行或模拟GROUP_CONCAT而不使用本机MySQL?

例如:

SELECT u.id, u.name, [GROUP_CONCAT(...)] AS user_messages
FROM models\Users u
LEFT JOIN models\Messages m
GROUP BY u.id

获取

GROUP_CONCAT(m.id,'|',m.title SEPARATOR ':')

目前我正在使用createNativeQuery()运行它,但我正在寻找一个Doctrine2的解决方案。

提前致谢。

2个回答

7

使用DoctrineExtensions可以实现这一点,它是由Doctrine2的核心开发者Beberlei开发的。在Doctrine2中,您可以通过扩展functionNode类来定义自己的查询表达式。

最简单的方法是将DoctrineExtensions库包含到您的项目中。我不知道您是否正在使用Zend Framework、Symfony或任何其他框架,因此无法帮助您嵌入它。

您可以在此处查看DoctrineExtensions:

https://github.com/beberlei/DoctrineExtensions

还有群组功能:

https://github.com/beberlei/DoctrineExtensions/blob/master/src/Query/Mysql/GroupConcat.php

请注意,在使用GroupConcat作为函数名称时,应该使用GroupConcat而不是MySQL中的GROUP_CONCAT。

希望这能帮助到您!


正是我所需要的。顺便说一下,我目前正在使用CodeIgniter,但我认为我可以成功地集成它。非常感谢。 - galchen

3

这是完整支持版本:

// -------------------------------------------------
// 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();


2
他们窃取了我自己编写的这个函数,请将信用归于此链接:http://habrahabr.ru/post/181666/(sysmagazine.com似乎对我的文章进行了自动翻译)。 - Denis V

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接